未验证 提交 36fb1f6a 编写于 作者: J Jialin, Sun 提交者: GitHub

Merge pull request #1519 from stdrickforce/nodejs

[Node.js] Add .eslintrc and fix warnings.
cmake*/
build/
package-lock.json
...@@ -2,6 +2,49 @@ ...@@ -2,6 +2,49 @@
`nodecat` supports node v8+. `nodecat` supports node v8+.
## Changelog
### 3.1.0
As everybody knows that node.js is an event-driven programming language. It's hard for us to trace messages.
Transactions can be intersected, makes it impossible to know which transaction is the parent of another one.
It caused problems, so we fallback the default mode to **atomic**, which means all messages will be sent immediately after it has been completed.
As the message tree is useful in some cases, we have introduced a brand new **Thread Mode** in this version.
In this mode, the **first** transaction will be the **root** transaction, all the following transactions and events will become its child nodes. Instead of being sent after themselves have been completed, the entire message tree will be sent after the root transaction (their parent) has been completed.
Here is the example usage.
```js
var cat = require('../lib')
cat.init({
appkey: 'nodecat'
})
cat = new cat.Cat(true)
let a = cat.newTransaction("Context", "A")
let b = cat.newTransaction("Context", "B")
let c = cat.newTransaction("Context", "C")
setTimeout(function() {
b.complete()
}, 1000)
setTimeout(function() {
c.complete()
}, 1500)
setTimeout(function() {
a.complete()
console.log("a complete")
}, 2000)
```
## Requirements ## Requirements
The `nodecat` required `libcatclient.so` to be installed in `LD_LIBRARY_PATH`. The `nodecat` required `libcatclient.so` to be installed in `LD_LIBRARY_PATH`.
......
...@@ -2,6 +2,49 @@ ...@@ -2,6 +2,49 @@
`nodecat` 支持 node v8 及以上版本。 `nodecat` 支持 node v8 及以上版本。
## Changelog
### 3.1.0
众所周知,node.js 是一个事件驱动的编程语言,这使得我们很难追踪消息。
Transaction 可以交错,令我们无法得知谁是谁的父节点。
这造成了一些问题,因此我们将默认模式降级为**原子模式**, 所有的消息在 complete 之后都会被立刻发送。
然而消息树在一些场景下很有用,因此我们在这个版本提供了一种船新的**线程模式**
在这一模式下,第一个 transaction 将会被作为根结点,随后所有的 transaction 和 event 都会被作为子节点。他们不会在 complete 之后被发送,取而代之的是在根结点 complete 后,整个消息树都会被发送。
这里有个例子:
```js
var cat = require('../lib')
cat.init({
appkey: 'nodecat'
})
cat = new cat.Cat(true)
let a = cat.newTransaction("Context", "A")
let b = cat.newTransaction("Context", "B")
let c = cat.newTransaction("Context", "C")
setTimeout(function() {
b.complete()
}, 1000)
setTimeout(function() {
c.complete()
}, 1500)
setTimeout(function() {
a.complete()
console.log("a complete")
}, 2000)
```
## Requirements ## Requirements
`nodecat` 需要 `libcatclient.so` 被安装在 `LD_LIBRARY_PATH` 目录下。 `nodecat` 需要 `libcatclient.so` 被安装在 `LD_LIBRARY_PATH` 目录下。
......
...@@ -23,3 +23,5 @@ for (var i = 0; i < 10; i++) { ...@@ -23,3 +23,5 @@ for (var i = 0; i < 10; i++) {
// In this case, the object will be dumped into json. // In this case, the object will be dumped into json.
cat.logEvent("Event", "E5", "failed", {a: 1, b: 2}) cat.logEvent("Event", "E5", "failed", {a: 1, b: 2})
} }
console.log('event end')
var cat = require('../lib')
cat.init({
appkey: 'nodecat'
})
cat = new cat.Cat(true)
let a = cat.newTransaction("Context", "A")
let b = cat.newTransaction("Context", "B")
let c = cat.newTransaction("Context", "C")
setTimeout(function() {
b.complete()
}, 1000)
setTimeout(function() {
c.complete()
}, 1500)
setTimeout(function() {
a.complete()
console.log("a complete")
}, 2000)
...@@ -7,7 +7,7 @@ const TreeManager = require('./message/org/tree-manager') ...@@ -7,7 +7,7 @@ const TreeManager = require('./message/org/tree-manager')
const STATUS = require('./constant').STATUS const STATUS = require('./constant').STATUS
const system = require('./system') const system = require('./system')
let isInitialized = false; let isInitialized = false
class TransactionHandler { class TransactionHandler {
constructor(transactionMessage, catInstance, threadMode) { constructor(transactionMessage, catInstance, threadMode) {
...@@ -29,7 +29,7 @@ class TransactionHandler { ...@@ -29,7 +29,7 @@ class TransactionHandler {
/** /**
* Add data to a transaction. * Add data to a transaction.
* 序列化成 query的形式 &key=value * 序列化成 query 的形式 &key=value
* 允许多次addData * 允许多次addData
* @param {string} key , 如果value存在则作为key,否则作为完整的data * @param {string} key , 如果value存在则作为key,否则作为完整的data
* @param {string} [value] * @param {string} [value]
...@@ -48,10 +48,9 @@ class TransactionHandler { ...@@ -48,10 +48,9 @@ class TransactionHandler {
/** /**
* end a transaction. * end a transaction.
* @param {number} maxTime
*/ */
complete(maxTime) { complete() {
this.treeManager.endMessage(this.message, maxTime) this.treeManager.endMessage(this.message)
} }
/** /**
...@@ -76,12 +75,11 @@ class TransactionHandler { ...@@ -76,12 +75,11 @@ class TransactionHandler {
if (this.threadMode) { if (this.threadMode) {
this.message.addChild(message) this.message.addChild(message)
} }
let t = new TransactionHandler(message, this.cat, this.threadMode) return new TransactionHandler(message, this.cat, this.threadMode)
return t
} }
/** /**
* logError , 同cat.logError , 但确保挂在此transaction下 * logError , 同 cat.logError , 但确保挂在此transaction下
*/ */
logError(name, error) { logError(name, error) {
let message = this.message let message = this.message
...@@ -96,7 +94,7 @@ class TransactionHandler { ...@@ -96,7 +94,7 @@ class TransactionHandler {
/** /**
* Class Cat * Class Cat
* 暴露给用户的API在这边,以这里的参数说明为准 * 暴露给用户的API在这边,以这里的参数说明为准
* */ */
class Cat { class Cat {
constructor(threadMode) { constructor(threadMode) {
this.STATUS = STATUS this.STATUS = STATUS
...@@ -155,13 +153,12 @@ class Cat { ...@@ -155,13 +153,12 @@ class Cat {
newTransaction(type, name) { newTransaction(type, name) {
type = '' + type type = '' + type
name = '' + name name = '' + name
var message = new TransactionMessage({ let message = new TransactionMessage({
type: type, type: type,
name: name name: name
}) })
this.treeManager.addMessage(message) this.treeManager.addMessage(message)
let t = new TransactionHandler(message, this, this.threadMode) return new TransactionHandler(message, this, this.threadMode)
return t
} }
complete() { complete() {
......
...@@ -3,13 +3,14 @@ const os = require('os') ...@@ -3,13 +3,14 @@ const os = require('os')
const logger = require('./logger.js')('config') const logger = require('./logger.js')('config')
const getLocalIP = () => { const getLocalIP = () => {
var ip = process.env.HOST_IP let ip = process.env.HOST_IP
if (!ip) { if (!ip) {
var interfaces = os.networkInterfaces() let interfaces = os.networkInterfaces()
var addresses = [] let addresses = []
for (var k in interfaces) {
for (var k2 in interfaces[k]) { for (let k of Object.values(interfaces)) {
var address = interfaces[k][k2] for (let k2 of k) {
let address = k2
if (address.family === 'IPv4' && !address.internal) { if (address.family === 'IPv4' && !address.internal) {
addresses.push(address.address) addresses.push(address.address)
} }
...@@ -22,7 +23,7 @@ const getLocalIP = () => { ...@@ -22,7 +23,7 @@ const getLocalIP = () => {
} }
// exports // exports
var config = { let config = {
maxMessageLength: 2000, maxMessageLength: 2000,
hostname: os.hostname(), hostname: os.hostname(),
domain: 'node-cat', domain: 'node-cat',
......
...@@ -4,10 +4,11 @@ const Event = require('../message/event') ...@@ -4,10 +4,11 @@ const Event = require('../message/event')
exports.init = (appKey) => { exports.init = (appKey) => {
CCatApi.init(appKey) CCatApi.init(appKey)
process.on('exit', (code) => { process.on('exit', () => {
try { try {
CCatApi.destroy() CCatApi.destroy()
} catch (e) { } catch (e) {
// do nothing.
} }
}) })
} }
......
module.exports = function (filename) { module.exports = function () {
return { return {
error: function (msg) { error: function (msg) {
console.log(msg); console.log(msg)
}, },
info: function (msg) { info: function (msg) {
console.log(msg); console.log(msg)
}, },
warn: function (msg) { warn: function (msg) {
console.log(msg); console.log(msg)
} }
} }
} }
\ No newline at end of file
'use strict' 'use strict'
var Message = require('./message') let Message = require('./message')
/** /**
* Get an instance of an event * Get an instance of an event
......
'use strict' 'use strict'
var Message = require('./message') let Message = require('./message')
var config = require('../config')() let config = require('../config')()
class Heartbeat extends Message { class Heartbeat extends Message {
constructor(options) { constructor(options) {
......
'use strict' 'use strict'
var HOUR = 3600 * 1000 let HOUR = 3600 * 1000
var cluster = require('cluster') let cluster = require('cluster')
var config = require('../config')() let config = require('../config')()
var assert = require('assert') let assert = require('assert')
var os = require('os') let os = require('os')
var cpuCount = os.cpus().length let cpuCount = os.cpus().length
var seq = initialSeq() let seq = initialSeq()
var hourTS let hourTS
let defaultIpHex
var defaultIpHex
if (config.ip) { if (config.ip) {
var ips = config.ip.split('.') let ips = config.ip.split('.')
assert.equal(ips.length, 4, 'ip must contains 4 groups') assert.equal(ips.length, 4, 'ip must contains 4 groups')
var buffer = new Buffer(4)
for (var i = 0; i < 4; ++i) { let buffer = new Buffer(4)
for (let i = 0; i < 4; ++i) {
buffer.writeUInt8(parseInt(ips[i]), i) buffer.writeUInt8(parseInt(ips[i]), i)
} }
defaultIpHex = '' defaultIpHex = ''
for (var j = 0; j < buffer.length; j++) { for (let j = 0; j < buffer.length; j++) {
var b = buffer.readUInt8(j) let b = buffer.readUInt8(j)
defaultIpHex += ((b >> 4) & 0x0f).toString(16) defaultIpHex += ((b >> 4) & 0x0f).toString(16)
defaultIpHex += (b & 0x0f).toString(16) defaultIpHex += (b & 0x0f).toString(16)
} }
} }
module.exports.nextId = function (domain) { module.exports.nextId = function (domain) {
var ts = Math.floor(Date.now() / HOUR) let ts = Math.floor(Date.now() / HOUR)
if (ts != hourTS) { if (ts !== hourTS) {
seq = initialSeq() seq = initialSeq()
hourTS = ts hourTS = ts
} }
...@@ -51,14 +53,14 @@ function MessageId(domain, hexIp, timestamp, index) { ...@@ -51,14 +53,14 @@ function MessageId(domain, hexIp, timestamp, index) {
module.exports.parse = function (messageId) { module.exports.parse = function (messageId) {
if (!messageId) return null if (!messageId) return null
var list = messageId.split('-') let list = messageId.split('-')
var len = list.length let len = list.length
if (len >= 4) { if (len >= 4) {
var ipAddressInHex = list[len - 3] let ipAddressInHex = list[len - 3]
var timestamp = parseInt(list[len - 2]) let timestamp = parseInt(list[len - 2])
var index = parseInt(list[len - 1]) let index = parseInt(list[len - 1])
var domain = list.splice(0, len - 3).join('-') let domain = list.splice(0, len - 3).join('-')
return new MessageId(domain, ipAddressInHex, timestamp, index) return new MessageId(domain, ipAddressInHex, timestamp, index)
} }
...@@ -66,12 +68,13 @@ module.exports.parse = function (messageId) { ...@@ -66,12 +68,13 @@ module.exports.parse = function (messageId) {
} }
module.exports.getIpAddress = function () { module.exports.getIpAddress = function () {
var local = this.hexIp let local = this.hexIp
var i = [] let ips = []
for (var i = 0, len = local.length; i < len; i += 2) {
var first = local.charAt(i) for (let i = 0, len = local.length; i < len; i += 2) {
var next = local.charAt(i + 1) let first = local.charAt(i)
var temp = 0 let next = local.charAt(i + 1)
let temp = 0
if (first >= '0' && first <= '9') { if (first >= '0' && first <= '9') {
temp += (first - '0') << 4 temp += (first - '0') << 4
...@@ -85,10 +88,10 @@ module.exports.getIpAddress = function () { ...@@ -85,10 +88,10 @@ module.exports.getIpAddress = function () {
temp += (next - 'a') + 10 temp += (next - 'a') + 10
} }
i.push(temp) ips.push(temp)
} }
return i.join('.') return ips.join('.')
} }
function initialSeq() { function initialSeq() {
......
...@@ -53,43 +53,31 @@ class Message { ...@@ -53,43 +53,31 @@ class Message {
this.beginTimestamp = +this.beginTime this.beginTimestamp = +this.beginTime
} }
end(maxTime) { end() {
if (this.isEnd) { if (this.isEnd) {
return return
} }
this.isEnd = true this.isEnd = true
let now = new Date() this.endTime = new Date()
if (maxTime) {
if (now - this.beginTime > maxTime) {
this.endTime = new Date(+this.beginTime + maxTime)
} else {
this.endTime = now
}
} else {
this.endTime = now
}
this.endTimestamp = +this.endTime this.endTimestamp = +this.endTime
} }
addChild(message) { addChild(...args) {
var self = this args.forEach(message => {
Array.prototype.forEach.call(arguments, message => { this.children.push(message)
self.children.push(message)
// message.parent = self
// 如果当前的已经结束,但是加进来的节点没有end // 如果当前的已经结束,但是加进来的节点没有end
if (self.allEnd && !message.isAllEnd()) { if (this.allEnd && !message.isAllEnd()) {
self.allEnd = false this.allEnd = false
} }
}) })
} }
removeChild() { removeChild(...args) {
var children = this.children args.forEach(message => {
Array.prototype.forEach.call(arguments, message => { let index = this.children.indexOf(message)
var index = children.indexOf(message)
if (index > -1) { if (index > -1) {
children.splice(index, 1) this.children.splice(index, 1)
message.parent = null message.parent = null
} }
}) })
...@@ -97,7 +85,7 @@ class Message { ...@@ -97,7 +85,7 @@ class Message {
} }
/** /**
* 是否自己和子节点全部都已经End * 是否自己和子节点全部都已经End
*/ */
isAllEnd() { isAllEnd() {
if (this.allEnd) { if (this.allEnd) {
......
'use strict' 'use strict'
var Tree = require('./tree') let Tree = require('./tree')
var Event = require('../event') let Event = require('../event')
var Transaction = require('../transaction') let Transaction = require('../transaction')
var Heartbeat = require('../heartbeat') let Heartbeat = require('../heartbeat')
class TreeManager { class TreeManager {
constructor(sender, threadMode) { constructor(sender, threadMode) {
...@@ -51,9 +51,9 @@ class TreeManager { ...@@ -51,9 +51,9 @@ class TreeManager {
/** /**
* 非线程模式,直接发送消息 * 非线程模式,直接发送消息
*/ */
endMessage(message, maxTime) { endMessage(message) {
// 先end自己 // 先end自己
message.end(maxTime) message.end()
if (!(message instanceof Transaction)) { if (!(message instanceof Transaction)) {
return return
......
...@@ -4,15 +4,15 @@ var moment = require('moment') ...@@ -4,15 +4,15 @@ var moment = require('moment')
function date2str(date) { function date2str(date) {
return moment(date).format('YYYY-MM-DD HH:mm:ss.SSS') return moment(date).format('YYYY-MM-DD HH:mm:ss.SSS')
}; }
function durationInMillis(start, end) { function durationInMillis(start, end) {
return (end - start) return (end - start)
}; }
function durationInMicros(start, end) { function durationInMicros(start, end) {
return (end - start) * 1000 return (end - start) * 1000
}; }
module.exports = { module.exports = {
date2str: date2str, date2str: date2str,
......
/**
* user child process to get disk space
* */
'use strict' 'use strict'
const exec = require('../util/shell').exec const exec = require('../util/shell').exec
const fs = require('fs') const fs = require('fs')
...@@ -15,11 +12,11 @@ if (process.platform === 'linux' || ...@@ -15,11 +12,11 @@ if (process.platform === 'linux' ||
return null return null
} }
try { try {
var res = yield exec("df -k '" + drive.replace(/'/g, "'\\''") + "'") let res = yield exec('df -k \'' + drive.replace(/'/g, '\'\\\'\'') + '\'')
var lines = res.trim().split('\n') let lines = res.trim().split('\n')
var strDiskInfo = lines[lines.length - 1].replace(/[\s\n\r]+/g, ' ') let strDiskInfo = lines[lines.length - 1].replace(/[\s\n\r]+/g, ' ')
var diskInfo = strDiskInfo.split(' ') let diskInfo = strDiskInfo.split(' ')
return { return {
available: diskInfo[3] * 1024, available: diskInfo[3] * 1024,
......
/**
* 获取系统的memory swap buffer/cache 使用情况
* 单位为byte
* */
'use strict' 'use strict'
var exec = require('../util/shell').exec
var os = require('os') let exec = require('../util/shell').exec
let os = require('os')
const DEFAULT_RESULT = { const DEFAULT_RESULT = {
totalMem: 0, totalMem: 0,
......
'use strict' 'use strict'
/**
* Base Class for System info
* */
class SystemBaseInfo { class SystemBaseInfo {
constructor(name, properties, content) { constructor(name, properties, content) {
this.name = name this.name = name
...@@ -13,8 +10,8 @@ class SystemBaseInfo { ...@@ -13,8 +10,8 @@ class SystemBaseInfo {
toString() { toString() {
// to xml item // to xml item
var tag = '<' + this.name let tag = '<' + this.name
var attrKeys = Object.keys(this.attrs) let attrKeys = Object.keys(this.attrs)
if (attrKeys.length) { if (attrKeys.length) {
tag += (' ' + attrKeys.map(key => key + '=' + '"' + this.attrs[key] + '"').join(' ')) tag += (' ' + attrKeys.map(key => key + '=' + '"' + this.attrs[key] + '"').join(' '))
} }
......
...@@ -5,12 +5,12 @@ const Time = require('../message/util/time') ...@@ -5,12 +5,12 @@ const Time = require('../message/util/time')
const Disk = require('./Disk') const Disk = require('./Disk')
const Mem = require('./Memory') const Mem = require('./Memory')
var userName = '' // let userName = ''
if (os.userInfo) { // if (os.userInfo) {
userName = os.userInfo().username // userName = os.userInfo().username
} else { // } else {
userName = require('child_process').execSync('whoami', {encoding: 'utf8', timeout: 1000}).replace('\n', '') // userName = require('child_process').execSync('whoami', {encoding: 'utf8', timeout: 1000}).replace('\n', '')
} // }
/** /**
* @return {SystemInfo} base system info * @return {SystemInfo} base system info
......
...@@ -9,13 +9,13 @@ let config = require('./config')() ...@@ -9,13 +9,13 @@ let config = require('./config')()
exports.collectStart = function (cat) { exports.collectStart = function (cat) {
if (process.env && process.env.pm_id) { if (process.env && process.env.pm_id) {
// in pm2 , only one worker does this collection // start exact one worker to collect cpu info in pm2.
try { try {
if (process.env.pm_id % os.cpus().length !== 0) { if (process.env.pm_id % os.cpus().length !== 0) {
return return
} }
} catch (e) { } catch (e) {
return
} }
} }
......
{ {
"name": "nodecat", "name": "nodecat",
"version": "3.0.0", "version": "3.1.0",
"description": "Cat client for Node.js.", "description": "Cat client for Node.js.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"moment": "^2.10.6", "moment": "^2.10.6",
"request": "^2.67.0", "request": "^2.67.0",
"xml2js": "^0.4.15" "xml2js": "^0.4.15",
"co": "latest"
}, },
"devDependencies": { "devDependencies": {
"cz-conventional-changelog": "^2.0.0", "cz-conventional-changelog": "^2.0.0",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册