├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── example
├── index.html
├── local-cache.html
└── saveCache.js
├── karma.conf.js
├── package.json
├── rollup.config.js
├── src
├── head
│ ├── base.ts
│ ├── error.ts
│ ├── observer.ts
│ ├── readme.md
│ └── whitescreen.ts
├── lib
│ ├── data.ts
│ ├── huffman.ts
│ ├── interface.ts
│ ├── spyHeadInterface.ts
│ └── util.ts
├── module
│ ├── fid.ts
│ ├── layoutShift.ts
│ ├── lcp.ts
│ ├── longtask.ts
│ ├── memory.ts
│ ├── navigatorInfo.ts
│ ├── resource.ts
│ ├── timing.ts
│ └── tti.ts
├── spy-client-basic.ts
├── spy-client.ts
├── spy-head.ts
├── spy-local-cache.ts
└── types
│ └── globals.d.ts
├── test
└── spec
│ ├── basicSpec.ts
│ ├── checkSpec.ts
│ ├── headSpec.ts
│ ├── markSpec.ts
│ ├── metricSpec.ts
│ └── types
│ └── globals.d.ts
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | output/
2 | dist/
3 | node_modules/
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @file eslintrc
3 | * @author kaivean
4 | */
5 |
6 | // reference to https://github.com/ecomfe/eslint-config
7 | module.exports = {
8 | extends: [
9 | '@ecomfe/eslint-config',
10 | // 注意这些规则会要求使用 ES6 的 import 来引入依赖,
11 | // 如果使用的是 require 则会出现检查错误,可禁用 import/no-commonjs 和 import/unambiguous 来解决。
12 | '@ecomfe/eslint-config/import',
13 | '@ecomfe/eslint-config/typescript'
14 | ],
15 | env: {
16 | 'jasmine': true,
17 | 'es6': true,
18 | 'browser': true,
19 | // 'node': true
20 | },
21 | rules: {
22 | 'no-unreachable-loop': 'off',
23 | 'no-console': ['error', {allow: ['warn', 'error']}],
24 | 'import/no-commonjs': 'off',
25 | 'import/unambiguous': 'off',
26 | 'import/extensions': 'off',
27 | 'import/no-unresolved': 'off',
28 | // for of 编译出来要多不少代码
29 | '@typescript-eslint/prefer-for-of': 'off',
30 | // 还是得写空函数得
31 | '@typescript-eslint/no-empty-function': 'off',
32 | // 数组includes方法,在浏览器需要polyfill,少用
33 | '@typescript-eslint/prefer-includes': 'off',
34 | // 字符串ends-with ,在浏览器需要polyfill,少用
35 | '@typescript-eslint/prefer-string-starts-ends-with': 'off',
36 | '@typescript-eslint/prefer-regexp-exec': 'off',
37 | '@typescript-eslint/restrict-plus-operands': 'off',
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Referenced from https://github.com/github/gitignore/blob/master/Node.gitignore
2 |
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # Bower dependency directory (https://bower.io/)
29 | bower_components
30 |
31 | # node-waf configuration
32 | .lock-wscript
33 |
34 | # Compiled binary addons (https://nodejs.org/api/addons.html)
35 | build/Release
36 |
37 | # Dependency directories
38 | node_modules/
39 | jspm_packages/
40 |
41 | # Typescript v1 declaration files
42 | typings/
43 |
44 | # Optional npm cache directory
45 | .npm
46 |
47 | # Optional eslint cache
48 | .eslintcache
49 |
50 | # Optional REPL history
51 | .node_repl_history
52 |
53 | # Output of 'npm pack'
54 | *.tgz
55 |
56 | # Yarn Integrity file
57 | .yarn-integrity
58 |
59 | # dotenv environment variables file
60 | .env
61 |
62 | # next.js build output
63 | .next
64 |
65 | # other stuff
66 | .DS_Store
67 | Thumbs.db
68 |
69 | .editorconfig
70 | .npmrc
71 |
72 | # IDE configurations
73 | .idea
74 | .vscode
75 |
76 | # build assets
77 | /output
78 | /dist
79 | /dll
80 |
81 | build-dep
82 | .cache-loader
83 |
84 | package-lock.json
85 |
86 | spy-client.d.ts
87 | spy-client.mjs
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /.settings
3 | /.project
4 | /.gitignore
5 | /node_modules
6 | /test
7 | /.tmp
8 | /.vscode
9 |
10 | .DS_Store
11 | *.db
12 | *.bak
13 | *.tmp
14 | *.cmd
15 | ~*
16 | package-lock.json
17 | tsconfig.json
18 | tsconfig.src.json
19 | tslint.json
20 |
21 | webpack.*.config.ts
22 | karma.conf.ts
23 |
24 | rollup.config.js
25 | .eslint*
26 | coverage
27 | src
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - '12'
5 |
6 | env:
7 | - TRAVIS=true
8 |
9 | addons:
10 | chrome: stable
11 |
12 | before_script:
13 | - "npm install"
14 | - "npm run build"
15 |
16 | script:
17 | - "npm run test"
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The ISC License
2 |
3 | Copyright (c) kaivean
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15 | IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # spy-client [](https://travis-ci.com/kaivean/spy-client)
2 |
3 | ## 介绍
4 | 日志采集模块,提供一系列方便的api供使用
5 |
6 | 1. 新版2.x部分API不再兼容1.x
7 | 2. 从2.1.0版本开始,不再兼容IE8及以下IE浏览器
8 | 3. 从2.1.8版本开始,兼容小程序环境(new Image类发送);通过继承类,覆盖request方法,可以支持Node.js/跨端框架/小程序环境
9 |
10 |
11 | ## 安装
12 |
13 | ```
14 | npm install spy-client --save
15 | ```
16 |
17 | CDN方式
18 |
19 | 不是一次性3个JS都引入,具体往下看
20 |
21 | ```html
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | ```
32 |
33 | > 如果对于一些指标想理解更准确,看源码是最佳方式 [SDK源码](https://github.com/kaivean/spy-client)
34 |
35 |
36 | > SDK的指标采集请酌情选用,不要一股脑全用上,如果只用了一项采集功能,但SDK体积太大,可以考虑自行编译,看文档最后
37 |
38 |
39 | ## 快速使用
40 |
41 | 初始化
42 | ```javascript
43 | const SpyClient = require('spy-client');
44 | const spy = new SpyClient({
45 | pid: '1_1000', // 必须
46 | lid: '', // 可选,页面的logid
47 | sample: 1 // 可选,默认为1, 全局抽样,取值:[0-1], 所有发送接口都受到该抽样,单个发送接口的sample配置会覆盖该抽样。
48 | });
49 | ```
50 |
51 | 发送性能日志
52 | ```javascript
53 | // 发送性能日志
54 | spy.sendPerf({
55 | // 可选, 分组,默认common,用户自定义
56 | group: 'test',
57 | // 必须, 指标信息,每个字段为一个指标,由用户自定义,这里的fisrtScreen、whiteScreen等都是业务自己定义,后续会在平台上配置好,平台会从该字段取对应指标信息。
58 | // 这些指标需要你自行计算好时间再发送,不能带单位
59 | info: {
60 | tcp: 1200,
61 | domReady: 600
62 | },
63 | // 可选,维度信息,每个字段为一个维度,由用户自定义,这里的netType、pageType都是业务自己定义,后续会在平台上配置好,平台会从该字段取对应维度信息。
64 | dim: {
65 | os: 'ios',
66 | netType: 'wifi'
67 | }
68 | });
69 | ```
70 |
71 | ## SDK说明
72 | SDK分两种
73 |
74 | * 基础版SDK:提供最基础和最简单的功能,如果这些功能能满足你,那么直接使用该SDK即可,因为体积较小
75 | * 增强版SDK:除了基础版SDK功能外,集合了丰富的常用的性能和异常指标统计
76 |
77 | 接下来分别介绍
78 |
79 | ## 基础版SDK
80 | 提供最基础和最简单的功能,如果这些功能能满足你,那么直接使用该SDK即可
81 |
82 | ```javascript
83 | // basic spy-client 基本用法,最简单功能
84 | const SpyClient = require('spy-client/dist/spy-client-basic');
85 | const spy = new SpyClient({
86 | pid: '1_1000', // 必须
87 | lid: '', // 可选,页面的logid
88 | sample: 1 // 可选,默认为1, 全局抽样,取值:[0-1], 所有发送接口都受到该抽样,单个发送接口的sample配置会覆盖该抽样。
89 | });
90 | ```
91 |
92 | 以下先简单列举所有可用API示例
93 | ```javascript
94 |
95 | // 发生性能日志,本质是数值型的metric数据
96 | spy.sendPerf({
97 | // 可选, 分组,默认common,用户自定义
98 | group: 'test',
99 | // 必须, 指标信息,每个字段为一个指标,由用户自定义,这里的fisrtScreen、whiteScreen等都是业务自己定义,后续会在平台上配置好,平台会从该字段取对应指标信息。
100 | // 这些指标需要你自行计算好时间再发送,不能带单位
101 | info: {
102 | tcp: 1200,
103 | domReady: 600
104 | },
105 | // 可选,维度信息,每个字段为一个维度,由用户自定义,这里的netType、pageType都是业务自己定义,后续会在平台上配置好,平台会从该字段取对应维度信息。
106 | dim: {
107 | os: 'ios',
108 | netType: 'wifi'
109 | }
110 | });
111 |
112 |
113 | // 发送异常日志
114 | spy.sendExcept({
115 | // 必须, 异常信息,msg字段是必须的,是异常唯一标识。其他字段作为补充信息,由用户自定义
116 | info: {
117 | msg: 'abc is not undefined', // msg字段是必须的,必须的,必须的,会统计相同msg的总量
118 | stack: 'xxxxx',
119 | file: 'xxxxxxx'
120 | },
121 | // 可选, 分组,默认common,用户自定义
122 | group: 'test',
123 | // 可选,维度信息,每个字段为一个维度,由用户自定义
124 | dim: {
125 | os: 'ios'
126 | }
127 | });
128 |
129 | // 发送分布日志
130 | spy.sendDist({
131 | info: {
132 | from: 'hao123'
133 | },
134 | dim: {
135 | os: 'ios'
136 | }
137 | });
138 |
139 | // 发送计数日志
140 | spy.sendCount({
141 | info: {
142 | from: 'hao123'
143 | },
144 | dim: {
145 | os: 'ios'
146 | }
147 | });
148 |
149 | // 如果能拿到error实例,通过该方法快速上报异常,默认会获取stack等信息
150 | spy.sendExceptForError(new Error('error'), {
151 | dim: {
152 | os: 'ios'
153 | }
154 | });
155 |
156 | // 最基础的API,需要自行指定type字段
157 | spy.send({
158 | type: 'perf'
159 | info: {
160 | domReady: 1000
161 | },
162 | dim: {}
163 | });
164 |
165 |
166 | // 统计辅助方法
167 | spy.startMark('playTime');
168 | let time = spy.endMark('playTime');
169 | console.log(time); // output: 1000
170 |
171 | spy.startMark('pauseTime');
172 | spy.endMark('pauseTime'); // 假设中间执行花费1s
173 | console.log(spy.getAllMark());
174 | // output
175 | // {
176 | // playTime: 1000,
177 | // pauseTime: 1000
178 | // }
179 |
180 | spy.clearMark('pauseTime'); // 清除pauseTime
181 | spy.clearAllMark(); // 清除所有mark的信息
182 |
183 | ```
184 |
185 | 基础版可支持小程序/Node.js/跨端框架环境
186 |
187 | 1 . 小程序
188 | 不用做任何修改,就支持采用new Image发送日志。
189 |
190 | 2 . Node.js/跨端框架环境
191 |
192 | Node.js,跨端框架,以及小程序环境中若采用`spy.send(xxx, true)`方式,则需要继承SpyClient类,覆盖request方法.
193 | 如果是Node.js,需要服务器有外网权限
194 |
195 | ```javascript
196 | const SpyClient = require('spy-client/dist/spy-client-basic');
197 | // 若环境编译不支持umd,则可以导入es module
198 | // const SpyClient = require('spy-client/dist/spy-client-basic.esm');
199 |
200 | class SpyClientNode from SpyClient {
201 | request(url: string, data?: any) {
202 | axios({
203 | method: data ? 'post' : 'get',
204 | url,
205 | data: data ? JSON.stringify(data) : data,
206 | });
207 | }
208 | }
209 |
210 | const spy = new SpyClientNode({
211 | pid: '1_1000', // 必须
212 | lid: '', // 可选,页面的logid
213 | sample: 1 // 可选,默认为1, 全局抽样,取值:[0-1], 所有发送接口都受到该抽样,单个发送接口的sample配置会覆盖该抽样。
214 | });
215 | spy.sendPerf({
216 | info: {
217 | responseTime: 200
218 | }
219 | });
220 | ```
221 |
222 | ## 增强版SDK
223 |
224 | 增强版SDK分成了2部分
225 |
226 | 1. spy-head:有些功能我们希望越早生效越好,比如全局JS报错监控。因此把这些功能最小集抽成一个单独JS,以便可以插入head标签内,也不会全量引入整个SDK在头部。当然,放到任何地方都是可以,开发者自行决策即可。此部分包含的功能有
227 | * 异常:全局JS报错监控、资源加载失败监控、白屏异常监控
228 | * 性能:Longtask等信息采集,真正的统计是在spy-client里,只是越早采集,能获取更多的longtask
229 |
230 | 2. spy-client:此部分提供了丰富的性能和异常的指标统计,其中部分功能依赖于spy-head,包含的功能有
231 | * 性能指标采集:包含体积、卡顿、速度等60+个性能指标采集方法
232 | * 异常:包含大于150K的大图片采集、HTTPS环境下HTTP资源采集
233 | * 辅助方式: mark系列辅助方法
234 |
235 | > 增强版SDK仅支持浏览器环境
236 |
237 | ### spy-head使用
238 |
239 | spy-head JS可以视情况通过script内联或嵌入其他JS里
240 |
241 | > 如果要启用一项异常监控功能,需要设置其抽样sample不为0
242 |
243 | ```html
244 |
9 |
43 |
44 |
45 |
46 |
47 |
open devtool
48 |
49 |
50 |
51 |
52 |
53 |
54 | TypeScriptJavaScriptJavaScript 的超集用于解决大型项目的代码复杂性一种脚本语言,用于创建动态网页。可以在编译期间发现并纠正错误作为一种解释型语言,只能在运行时发现错误强类型,支持静态和动态类型弱类型,没有静态类型选项最终被编译成 JavaScript 代码,使浏览器可以理解可以直接在浏览器中使用支持模块、泛型和接口不支持模块,泛型或接口支持 ES3,ES4,ES5 和 ES6 等不支持编译其他 ES3,ES4,ES5 或 ES6 功能社区的支持仍在增长,而且还不是很大大量的社区支持以及大量文档和解决问题的支持
55 |
56 |

57 |

58 |
59 |
60 |
61 |
62 |
63 |
338 |
339 |