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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 日志服务(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;
  }
}

总结

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

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
3月前
|
Java Apache 开发工具
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
|
3月前
|
SQL 存储 JSON
更快更强,SLS 推出高性能 SPL 日志查询模式
从海量的日志数据中,按照各种灵活的条件进行即时查询搜索,是可观测场景下的基本需求。本文介绍了 SLS 新推出的高性能 SPL 日志查询模式,支持 Unix 风格级联管道式语法,以及各种丰富的 SQL 处理函数。同时通过计算下推、向量化计算等优化,使得 SPL 查询可以在数秒内处理亿级数据,并支持 SPL 过滤结果分布图、随机翻页等特性。
12012 110
|
4月前
|
SQL Java Serverless
实时计算 Flink版操作报错合集之在写入SLS(Serverless Log Service)时出现报错,该如何排查
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
5月前
|
SQL 数据采集 DataWorks
DataWorks产品使用合集之pyodps的线程限制是什么意思
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
5月前
|
DataWorks 数据可视化 安全
DataWorks产品使用合集之SLS日志中新增了存在iotId这个字段,同步的时候怎么手动增加
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
1月前
FFmpeg【SDK01】日志和字典的使用
FFmpeg中日志功能的使用方法,包括日志级别的设置和AVDictionary的基本操作,同时展示了字符串解析函数如av_parse_video_size、av_parse_video_rate和av_parse_time的应用。
30 2
|
2月前
|
存储 监控 数据可视化
SLS 虽然不是直接使用 OSS 作为底层存储,但它凭借自身独特的存储架构和功能,为用户提供了一种专业、高效的日志服务解决方案。
【9月更文挑战第2天】SLS 虽然不是直接使用 OSS 作为底层存储,但它凭借自身独特的存储架构和功能,为用户提供了一种专业、高效的日志服务解决方案。
150 9
|
3月前
|
Java 开发工具
【Azure 事件中心】关闭或开启Azure Event Hub SDK中的日志输出
【Azure 事件中心】关闭或开启Azure Event Hub SDK中的日志输出
|
4月前
|
监控 数据管理 关系型数据库
数据管理DMS使用问题之是否支持将操作日志导出至阿里云日志服务(SLS)
阿里云数据管理DMS提供了全面的数据管理、数据库运维、数据安全、数据迁移与同步等功能,助力企业高效、安全地进行数据库管理和运维工作。以下是DMS产品使用合集的详细介绍。
|
3月前
|
存储 Kubernetes Java
阿里泛日志设计与实践问题之在写多查少的降本场景下,通过SLS Scan方案降低成本,如何实现
阿里泛日志设计与实践问题之在写多查少的降本场景下,通过SLS Scan方案降低成本,如何实现

相关产品

  • 日志服务