日志服务(SLS) 的桌面端 Node.js SDK 封装

简介: 日志服务(SLS) 的桌面端 Node.js SDK 封装

项目需求

项目上为了更好地掌握产品的使用数据,综合对比各种埋点框架之后决定基于自由度更高的日志服务(以下简称“SLS”)实现数据埋点。

SLS 官方提供的 SDK 非常丰富,包含十几种语言,而 JavaScript 更是受到了优厚待遇,相关 SDK 已经达到了 3 种:浏览器 JavaScript SDK、小程序 JavaScript SDK、Node.js SDK。

目前我们项目没有小程序,只有 Node.js 的桌面端以及 JavaScript 的浏览器端,所以不考虑小程序 JavaScript SDK。

浏览器 JavaScript SDK

浏览器 JavaScript SDK,可以通过 npm 方便地引入,在 web 页面上进行数据上报。

importSlsTrackerfrom'@aliyun-sls/web-track-browser';
constopts= {
host: '${host}', // 所在地域的服务入口。例如cn-hangzhou.log.aliyuncs.comproject: '${project}', // Project名称。logstore: '${logstore}', // Logstore名称。}

API 也相当简单,4个函数实现了同步和异步、单条和多条的数据上报。

image.png

符合项目需求,很顺利地就被引用了。

Node.js SDK

Node.js SDK 和浏览器 JavaScript SDK 提供的 API 相比,则提供了更为丰富的功能,不仅有日志数据上报,还加入了对日志库的管理操作。

image.png

不仅如此,使用的时候增加必传参数 AccessKeyID 和 AccessKeySecret。

constALY=require('aliyun-sdk')
varsls=newALY.SLS({
accessKeyId: "11****ut",                         //阿里云访问密钥AccessKey ID。更多信息,请参见访问密钥。阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维。 secretAccessKey: "TS****7Y",                     //阿里云访问密钥AccessKey Secret。 endpoint: 'http://cn-hangzhou.log.aliyuncs.com', //日志服务的域名。更多信息,请参见服务入口。此处以杭州为例,其它地域请根据实际情况填写。apiVersion: '2015-06-01'//SDK版本号,固定值。  })
constprojectName="you_project_name"// 必选,Project名称。constlogstoreName="your_logstore_name"// 必选,Project描述。// 创建Project。functioncreateProject () {
constparam= {
projectDetail: {
projectName,                                  
description: "description about project"    }
  }
sls.createProject(param, function(err, data) {
if (err) {
console.error('error:', err)
    } else {
console.log('创建project', data)
    }
  })
}
// 运行function。createProject()

这两个特点就和桌面端的使用场景有些相悖了。

一方面桌面端也只需要进行数据上报,并不需要对日志库管理,丰富的功能有些冗余。另一方面作为支持公共写的日志库实际上并不需要这些配置信息,而且这些信息放在端上也存在安全风险。

那在桌面端上该怎么方便地上报日志数据呢?

解决思路

借用浏览器 JavaScript SDK

既然桌面端和浏览器一样都是用 JavaScript 写的,那是否可以直接在桌面端用浏览器 JavaScript SDK 呢?

很遗憾并不行,由于浏览器 JavaScript SDK 依赖了浏览器一些全局方法,会导致在 Node.js 中直接报错。

如果要强行在 Node.js 中运行,对其进行改造也是可以。

但是改造流程可能会比较长:

  • 拉取代码仓库。
  • 修改代码。
  • 提交 PR 合并后等新版本发布或者自行再建一个仓库发布到 (T)NPM。

这一番操作下来已是远水救不了近火,所以换个思路自行封装一个轻量的用于客户端的 Node.js SDK

基于官方 API 进行封装

首先考虑的是基于官方的 API 进行封装。

关于日志数据上报,官方提供了2个的方法: PostLogStoreLogsPutLogs 。这两个方法各有一些限制:

  • PostLogStoreLogs 只支持 PB格式的日志压缩数据。
  • PutLogs 需要传入 LogGroup、LogTag 这些参数。

除此之外,它们都有一个共同点:需要 AK 授权。

这和浏览器 JavaScript SDK 相比明显麻烦很多,既然这样,我们只能往更底层去挖掘可能性了~

基于官方 SDK 逆向研发

既然我们想要在桌面端实现一个功能和浏览器 JavaScript SDK 一样的 SDK,那么不妨先来了解它做了什么。

当我们调用 send 函数的时候,实际上并没有立即发送日志,而是在随后的轮询间隔中,以数组的形式将日志数据进行上报。

image.png

所以这里推测采用了队列来缓存日志数据,减少网络请求次数。

同时仔细观察还可以发现为了不占用网络线程,这里采用了浏览器 sendBeacon 方法而不是 XMLHTTPRequest 或者 fetch 的方式,如果浏览器不支持这个方法则降级为 POST 请求。但由于这个 API 是浏览器提供的,所以桌面端只考虑采用 POST 请求方式。

image.png

通过浏览器调试工具观察请求网址可以发现其规律

https://{project}.{host}/logstores/{logstore}/track?APIVersion=0.6.0

image.png

总结一下:

  1. 1.建立日志队列,延迟、定时发送。
  2. 2.按照固定格式发送 POST 请求。
  3. 3.支持立即发送,对应 SDK 的 sendImmediate 方法。(这一点是后面开发中才发现的需求,比如页面离开时需要立即发送日志,避免缓存的日志数据丢失)

具体实现

一般而言,对于无状态的封装可以考虑用(纯)函数。

而 SDK 不仅要传入 project、host、logstore 这些配置数据,还需要建立内部的缓存队列,所以对于这种有状态的场景考虑使用类 Class。

对应代码如下:

classSlsTracker {
_timeout=null; // 定时器实现延迟发送__logs__= []; // 缓存队列constructor({
host,
project,
logstore  }) {
// 配置信息this._host=host;
this._project=project;
this._logstore=logstore  }
}

至于延迟、定时发送的实现可以依赖 setTimeout 或 setInterval,由于发送应该是队列有值的时候才进行,所以 setInterval 轮询这种性能消耗较大的方式并不适用。

下面来考虑核心函数 send 的实现。

send 接收一个对象参数作为日志数据。所以现将它推送到队列,然后创立一个延迟的 POST 请求,但很可能之前已经创建了一个 POST 请求,所以通过 this._timeout 来判断,如果存在则不再创建。定到定时器触发时将队列所有数据发送。

这里需要注意的是,上报的数据值需要转换为字符串。

考虑到程序的鲁棒性,可以考虑限制队列长度和字符长度。

classSlsTracker {
......send(info){
this.__logs__.push(this._transString(info));    
constoptions= {
hostname: `${this._project}.${this._host}`,
port: 443,
path: `/logstores/${this._logstore}/track?APIVersion=0.6.0`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
      }
    }
if (this._timeout) return;
this._timeout=setTimeout((o) => {
constpayload=JSON.stringify({ __logs__: this.__logs__ });
o.headers['Content-Length'] =Buffer.byteLength(payload)
constreq=https.request(o)
req.write(payload);
req.end();
this.__logs__= [];
this._timeout=null;
    }, this._time, options);
  }
.......
}

至于立即发送日志数据实现就相对容易了,取消之前定时器直接发送请求即可。

classSlsTracker {
......sendImmediate() {
constpayload=JSON.stringify({ __logs__: this.__logs__ });
consto= {
hostname: `${this._project}.${this._host}`,
port: 443,
path: `/logstores/${this._logstore}/track?APIVersion=0.6.0`,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload)
      }
    }
constreq=https.request(o)
req.write(payload);
req.end();
this.__logs__= [];
clearTimeout(this._timeout);
this._timeout=null;
  }
}

总结

在依赖的代码库或平台不能满足要求时,首先考虑基于已有的信息自行进行研发,实在不行逆向研发也未尝不可。

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
6月前
|
存储 JavaScript API
百宝箱开放平台 ✖️ Node.js SDK
开发者可以通过安装 Node.js SDK 的方式将百宝箱的 OpenAPI 集成到自有系统中,从而在外部系统中发起智能体对话。
339 0
百宝箱开放平台 ✖️ Node.js SDK
|
11月前
|
监控 容灾 算法
阿里云 SLS 多云日志接入最佳实践:链路、成本与高可用性优化
本文探讨了如何高效、经济且可靠地将海外应用与基础设施日志统一采集至阿里云日志服务(SLS),解决全球化业务扩展中的关键挑战。重点介绍了高性能日志采集Agent(iLogtail/LoongCollector)在海外场景的应用,推荐使用LoongCollector以获得更优的稳定性和网络容错能力。同时分析了多种网络接入方案,包括公网直连、全球加速优化、阿里云内网及专线/CEN/VPN接入等,并提供了成本优化策略和多目标发送配置指导,帮助企业构建稳定、低成本、高可用的全球日志系统。
1043 54
|
Kubernetes Ubuntu Windows
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
【Azure K8S | AKS】分享从AKS集群的Node中查看日志的方法(/var/log)
412 3
|
SQL 存储 JSON
更快更强,SLS 推出高性能 SPL 日志查询模式
从海量的日志数据中,按照各种灵活的条件进行即时查询搜索,是可观测场景下的基本需求。本文介绍了 SLS 新推出的高性能 SPL 日志查询模式,支持 Unix 风格级联管道式语法,以及各种丰富的 SQL 处理函数。同时通过计算下推、向量化计算等优化,使得 SPL 查询可以在数秒内处理亿级数据,并支持 SPL 过滤结果分布图、随机翻页等特性。
13631 218
|
JSON 监控 JavaScript
Node.js-API 限流与日志优化
Node.js-API 限流与日志优化
|
JavaScript 前端开发 开发工具
【Azure Developer】使用JavaScript通过SDK进行monitor-query的client认证报错问题
AADSTS90002: Tenant 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' not found. Check to make sure you have the correct tenant ID and are signing into the correct cloud. Check with your subscription administrator, this may happen if there are no active subscriptions for the tenant.
169 1
|
存储 监控 数据可视化
SLS 虽然不是直接使用 OSS 作为底层存储,但它凭借自身独特的存储架构和功能,为用户提供了一种专业、高效的日志服务解决方案。
【9月更文挑战第2天】SLS 虽然不是直接使用 OSS 作为底层存储,但它凭借自身独特的存储架构和功能,为用户提供了一种专业、高效的日志服务解决方案。
631 9
|
JavaScript Serverless Linux
函数计算产品使用问题之遇到Node.js环境下的请求日志没有正常输出时,该如何排查
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
存储 Kubernetes Java
阿里泛日志设计与实践问题之在写多查少的降本场景下,通过SLS Scan方案降低成本,如何实现
阿里泛日志设计与实践问题之在写多查少的降本场景下,通过SLS Scan方案降低成本,如何实现
212 0

相关产品

  • 日志服务