Refactor the span context to use ALS
diff --git a/Dockerfile.agent.test b/Dockerfile.agent.test
deleted file mode 100644
index 0e66a05..0000000
--- a/Dockerfile.agent.test
+++ /dev/null
@@ -1,22 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-FROM node:12
-
-WORKDIR /dependencies
-
-COPY package.json .
-
-RUN npm install
diff --git a/package-lock.json b/package-lock.json
index ca345e1..a4570cf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
- "name": "@ali/skywalking-nodejs",
- "version": "0.0.21-RC",
+ "name": "skywalking",
+ "version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1591,18 +1591,250 @@
}
},
"grpc-tools": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/grpc-tools/-/grpc-tools-1.9.0.tgz",
- "integrity": "sha512-du10qytFNDVNYGJQ/AxXTF6lXchgCZ7ls8BtBDCtnuinjGbnPFHpOIzoEAT8NsmgFg4RCpsWW8vsQ+RCyQ3SXA==",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/grpc-tools/-/grpc-tools-1.8.0.tgz",
+ "integrity": "sha512-GzYHjPQ/sbV/DmnNRksapMlLj26Tvq2Qppmzjmd+lHYZNeWM1feiGsYCduzJLyy295P+3uYIPy2/w/1thAnOow==",
"dev": true,
"requires": {
"node-pre-gyp": "^0.12.0"
},
"dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true,
+ "dev": true
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true,
+ "dev": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true,
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "bundled": true,
+ "dev": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "bundled": true,
+ "dev": true
+ },
+ "fs-minipass": {
+ "version": "1.2.5",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.3",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "bundled": true,
+ "dev": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true,
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true,
+ "dev": true
+ },
+ "minipass": {
+ "version": "2.3.5",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "needle": {
+ "version": "2.2.4",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "debug": "^2.1.2",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
"node-pre-gyp": {
"version": "0.12.0",
- "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
- "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
+ "bundled": true,
"dev": true,
"requires": {
"detect-libc": "^1.0.2",
@@ -1615,15 +1847,226 @@
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.6",
+ "bundled": true,
+ "dev": true
+ },
+ "npm-packlist": {
+ "version": "1.4.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true,
+ "dev": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "rc": {
+ "version": "1.2.8",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
},
"dependencies": {
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true,
"dev": true
}
}
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "bundled": true,
+ "dev": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true,
+ "dev": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true,
+ "dev": true
+ },
+ "semver": {
+ "version": "5.6.0",
+ "bundled": true,
+ "dev": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true,
+ "dev": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true,
+ "dev": true
+ },
+ "tar": {
+ "version": "4.4.8",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.4",
+ "minizlib": "^1.1.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.2"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true,
+ "dev": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "bundled": true,
+ "dev": true
}
}
},
@@ -4092,9 +4535,9 @@
}
},
"tslib": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
- "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-2.0.3.tgz?cache=0&sync_timestamp=1602286724979&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftslib%2Fdownload%2Ftslib-2.0.3.tgz",
+ "integrity": "sha1-jgdBrEX8DCJuWKF7/D5kubxsphw=",
"dev": true
},
"tslint": {
@@ -4123,6 +4566,12 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-1.14.1.tgz?cache=0&sync_timestamp=1602286724979&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftslib%2Fdownload%2Ftslib-1.14.1.tgz",
+ "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=",
+ "dev": true
}
}
},
@@ -4139,6 +4588,14 @@
"dev": true,
"requires": {
"tslib": "^1.8.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-1.14.1.tgz?cache=0&sync_timestamp=1602286724979&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftslib%2Fdownload%2Ftslib-1.14.1.tgz",
+ "integrity": "sha1-zy04vcNKE0vK8QkcQfZhni9nLQA=",
+ "dev": true
+ }
}
},
"type-detect": {
diff --git a/package.json b/package.json
index 69656c5..094963e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "skywalking",
- "version": "0.0.1",
+ "version": "0.1.0",
"description": "The NodeJS agent for Apache SkyWalking",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -11,11 +11,7 @@
"lint": "tslint -p tsconfig.json",
"test": "mocha -r ts-node/register 'tests/**/test.ts'",
"format": "prettier --write \"src/**/*.ts\"",
- "clean": "(rm -rf src/proto || true) && (rm -rf src/proto || true) && (rm -rf lib || true)",
- "dev": "node node_modules/ts-node/dist/bin -r tsconfig-paths/register tests/dev.ts"
- },
- "publishConfig": {
- "registry": "https://registry.npm.alibaba-inc.com"
+ "clean": "(rm -rf src/proto || true) && (rm -rf src/proto || true) && (rm -rf lib || true)"
},
"files": [
"lib/**/*"
@@ -24,12 +20,14 @@
"SkyWalking",
"APM",
"Dapper",
- "Tracing"
+ "Tracing",
+ "Agent",
+ "Instrumentation"
],
"author": "Apache SkyWalking Team",
"license": "Apache 2.0",
"bugs": {
- "url": "http://github.com/apache/skywalking/issues",
+ "url": "https://github.com/apache/skywalking/issues",
"email": "dev@skywalking.apache.org"
},
"devDependencies": {
@@ -41,7 +39,7 @@
"@types/semver": "^7.2.0",
"@types/uuid": "^8.0.0",
"chai": "^4.2.0",
- "grpc-tools": "^1.9.0",
+ "grpc-tools": "^1.8.0",
"grpc_tools_node_protoc_ts": "^4.0.0",
"mocha": "^8.0.1",
"mongodb": "^3.5.9",
@@ -49,6 +47,7 @@
"prettier": "^2.0.5",
"ts-node": "^8.10.2",
"tsconfig-paths": "^3.9.0",
+ "tslib": "^2.0.3",
"tslint": "^6.1.2",
"tslint-config-prettier": "^1.18.0",
"typescript": "^3.9.5",
diff --git a/src/agent/protocol/grpc/SegmentObjectAdapter.ts b/src/agent/protocol/grpc/SegmentObjectAdapter.ts
index 0ffa8e8..2844763 100644
--- a/src/agent/protocol/grpc/SegmentObjectAdapter.ts
+++ b/src/agent/protocol/grpc/SegmentObjectAdapter.ts
@@ -28,46 +28,61 @@
export default class SegmentObjectAdapter extends SegmentObject {
constructor(segment: Segment) {
super();
- this.setService(config.serviceName)
- .setServiceinstance(config.serviceInstance)
- .setTraceid(segment.relatedTraces[0].toString())
- .setTracesegmentid(segment.segmentId.toString())
- .setSpansList(
- segment.spans.map((span) =>
- new SpanObject()
- .setSpanid(span.id)
- .setParentspanid(span.parentId)
- .setStarttime(span.startTime)
- .setEndtime(span.endTime)
- .setOperationname(span.operation)
- .setPeer(span.peer)
- .setSpantype(span.type)
- .setSpanlayer(span.layer)
- .setComponentid(span.component.id)
- .setIserror(span.errored)
- .setLogsList(
- span.logs.map((log) =>
- new Log()
- .setTime(log.timestamp)
- .setDataList(
- log.items.map((logItem) => new KeyStringValuePair().setKey(logItem.key).setValue(logItem.val)),
- ),
- ),
- )
- .setTagsList(span.tags.map((tag) => new KeyStringValuePair().setKey(tag.key).setValue(tag.val)))
- .setRefsList(
- span.refs.map((ref) =>
- new SegmentReference()
- .setReftype(RefType.CROSSPROCESS)
- .setTraceid(ref.traceId.toString())
- .setParenttracesegmentid(ref.segmentId.toString())
- .setParentspanid(ref.spanId)
- .setParentservice(ref.service)
- .setParentserviceinstance(ref.serviceInstance)
- .setNetworkaddressusedatpeer(ref.clientAddress),
- ),
- ),
- ),
- );
+ this.setService(config.serviceName);
+ this.setServiceinstance(config.serviceInstance);
+ this.setTraceid(segment.relatedTraces[0].toString());
+ this.setTracesegmentid(segment.segmentId.toString());
+ this.setSpansList(
+ segment.spans.map((span) => {
+ const spanObj = new SpanObject();
+ spanObj.setSpanid(span.id);
+ spanObj.setParentspanid(span.parentId);
+ spanObj.setStarttime(span.startTime);
+ spanObj.setEndtime(span.endTime);
+ spanObj.setOperationname(span.operation);
+ spanObj.setPeer(span.peer);
+ spanObj.setSpantype(span.type);
+ spanObj.setSpanlayer(span.layer);
+ spanObj.setComponentid(span.component.id);
+ spanObj.setIserror(span.errored);
+ spanObj.setLogsList(
+ span.logs.map((log) => {
+ const l = new Log();
+ l.setTime(log.timestamp);
+ l.setDataList(
+ log.items.map((logItem) => {
+ const item = new KeyStringValuePair();
+ item.setKey(logItem.key);
+ item.setValue(logItem.val);
+ return item;
+ }),
+ );
+ return l;
+ }),
+ );
+ spanObj.setTagsList(
+ span.tags.map((tag) => {
+ const item = new KeyStringValuePair();
+ item.setKey(tag.key);
+ item.setValue(tag.val);
+ return item;
+ }),
+ );
+ spanObj.setRefsList(
+ span.refs.map((ref) => {
+ const segmentRef = new SegmentReference();
+ segmentRef.setReftype(RefType.CROSSPROCESS);
+ segmentRef.setTraceid(ref.traceId.toString());
+ segmentRef.setParenttracesegmentid(ref.segmentId.toString());
+ segmentRef.setParentspanid(ref.spanId);
+ segmentRef.setParentservice(ref.service);
+ segmentRef.setParentserviceinstance(ref.serviceInstance);
+ segmentRef.setNetworkaddressusedatpeer(ref.clientAddress);
+ return segmentRef;
+ }),
+ );
+ return spanObj;
+ }),
+ );
}
}
diff --git a/src/agent/protocol/grpc/clients/HeartbeatClient.ts b/src/agent/protocol/grpc/clients/HeartbeatClient.ts
index 3c51713..5bebc81 100644
--- a/src/agent/protocol/grpc/clients/HeartbeatClient.ts
+++ b/src/agent/protocol/grpc/clients/HeartbeatClient.ts
@@ -56,19 +56,39 @@
return;
}
- const keepAlivePkg = new InstancePingPkg()
- .setService(config.serviceName)
- .setServiceinstance(config.serviceInstance);
+ const keepAlivePkg = new InstancePingPkg();
+ keepAlivePkg.setService(config.serviceName);
+ keepAlivePkg.setServiceinstance(config.serviceInstance);
- const instanceProperties = new InstanceProperties()
- .setService(config.serviceName)
- .setServiceinstance(config.serviceInstance)
- .setPropertiesList([
- new KeyStringValuePair().setKey('language').setValue('NodeJS'),
- new KeyStringValuePair().setKey('OS Name').setValue(os.platform()),
- new KeyStringValuePair().setValue('hostname').setValue(os.hostname()),
- new KeyStringValuePair().setValue('Process No.').setValue(`${process.pid}`),
- ]);
+ const instanceProperties = new InstanceProperties();
+ instanceProperties.setService(config.serviceName);
+ instanceProperties.setServiceinstance(config.serviceInstance);
+ instanceProperties.setPropertiesList([
+ (() => {
+ const lang = new KeyStringValuePair();
+ lang.setKey('language');
+ lang.setValue('NodeJS');
+ return lang;
+ })(),
+ (() => {
+ const osName = new KeyStringValuePair();
+ osName.setKey('OS Name');
+ osName.setValue(os.platform());
+ return osName;
+ })(),
+ (() => {
+ const hostname = new KeyStringValuePair();
+ hostname.setValue('hostname');
+ hostname.setValue(os.hostname());
+ return hostname;
+ })(),
+ (() => {
+ const p = new KeyStringValuePair();
+ p.setValue('Process No.');
+ p.setValue(`${process.pid}`);
+ return p;
+ })(),
+ ]);
this.heartbeatTimer = setInterval(() => {
this.heartbeatClient.reportInstanceProperties(
diff --git a/src/plugins/HttpPlugin.ts b/src/plugins/HttpPlugin.ts
index a7caf18..56f8911 100644
--- a/src/plugins/HttpPlugin.ts
+++ b/src/plugins/HttpPlugin.ts
@@ -34,6 +34,9 @@
readonly versions = '*';
install(): void {
+ if (logger.isDebugEnabled()) {
+ logger.debug('installing http plugin');
+ }
this.interceptClientRequest();
this.interceptServerRequest();
}
@@ -43,11 +46,7 @@
((original) => {
http.request = function () {
- const argc = arguments.length;
-
const url: URL | string | RequestOptions = arguments[0];
- const options = argc > 1 ? (typeof arguments[1] === 'function' ? {} : arguments[1]) : {};
- const callback = typeof arguments[argc - 1] === 'function' ? arguments[argc - 1] : undefined;
const { host, pathname } =
url instanceof URL
@@ -65,32 +64,17 @@
span.layer = SpanLayer.HTTP;
span.tag(Tag.httpURL(host + pathname));
- const snapshot = ContextManager.current.capture();
-
const request: ClientRequest = original.apply(this, arguments);
span.extract().items.forEach((item) => {
request.setHeader(item.key, item.value);
});
- request.on('response', (res) => {
- res.prependListener('end', () => {
- span.tag(Tag.httpStatusCode(res.statusCode)).tag(Tag.httpStatusMsg(res.statusMessage));
+ span.async();
- const callbackSpan = ContextManager.current.newLocalSpan('callback').start();
- callbackSpan.layer = SpanLayer.HTTP;
- callbackSpan.component = Component.HTTP;
-
- ContextManager.current.restore(snapshot);
-
- if (callback) {
- callback(res);
- }
-
- callbackSpan.stop();
- });
+ request.on('close', () => {
+ span.await().stop();
});
- span.stop();
return request;
};
@@ -106,26 +90,36 @@
return original.apply(this, arguments);
}
- const [req, res] = [arguments[1] as IncomingMessage, arguments[2] as ServerResponse];
+ const args = arguments;
+ const self = this;
- const headers = req.rawHeaders || [];
- const headersMap: { [key: string]: string } = {};
+ return ContextManager.withContext(() => {
+ const [req, res] = [args[1] as IncomingMessage, args[2] as ServerResponse];
- for (let i = 0; i < headers.length / 2; i += 2) {
- headersMap[headers[i]] = headers[i + 1];
- }
+ const headers = req.rawHeaders || [];
+ const headersMap: { [key: string]: string } = {};
- const carrier = ContextCarrier.from(headersMap);
+ for (let i = 0; i < headers.length / 2; i += 2) {
+ headersMap[headers[i]] = headers[i + 1];
+ }
- const span = ContextManager.current.newEntrySpan('/', carrier).start();
- span.operation = (req.url || '/').replace(/\?.*/g, '');
- span.component = Component.HTTP_SERVER;
- span.layer = SpanLayer.HTTP;
- span.tag(Tag.httpURL(req.url));
+ const carrier = ContextCarrier.from(headersMap);
- span.tag(Tag.httpStatusCode(res.statusCode)).tag(Tag.httpStatusMsg(res.statusMessage)).stop();
+ const span = ContextManager.current.newEntrySpan('/', carrier).start();
+ span.operation = (req.url || '/').replace(/\?.*/g, '');
+ span.component = Component.HTTP_SERVER;
+ span.layer = SpanLayer.HTTP;
+ span.tag(Tag.httpURL(req.url));
- return original.apply(this, arguments);
+ span.tag(Tag.httpStatusCode(res.statusCode)).tag(Tag.httpStatusMsg(res.statusMessage));
+
+ res.on('close', () => {
+ console.info('jjj');
+ span.stop();
+ });
+
+ return original.apply(self, args);
+ });
};
})(http.Server.prototype.emit);
}
diff --git a/src/trace/context/Context.ts b/src/trace/context/Context.ts
index 7393887..984033d 100644
--- a/src/trace/context/Context.ts
+++ b/src/trace/context/Context.ts
@@ -41,4 +41,8 @@
capture(): Snapshot;
restore(snapshot: Snapshot): void;
+
+ async(span: Span): void;
+
+ await(span: Span): void;
}
diff --git a/src/trace/context/ContextCarrier.ts b/src/trace/context/ContextCarrier.ts
index c8f046f..8d94053 100644
--- a/src/trace/context/ContextCarrier.ts
+++ b/src/trace/context/ContextCarrier.ts
@@ -46,13 +46,13 @@
get value(): string {
return [
'1',
- this.encode(this.traceId!.toString()),
- this.encode(this.segmentId!.toString()),
- this.spanId!.toString(),
- this.encode(this.service!),
- this.encode(this.serviceInstance!),
- this.encode(this.endpoint!),
- this.encode(this.clientAddress!),
+ this.encode(this.traceId?.toString() || ''),
+ this.encode(this.segmentId?.toString() || ''),
+ this.spanId?.toString(),
+ this.encode(this.service || ''),
+ this.encode(this.serviceInstance || ''),
+ this.encode(this.endpoint || ''),
+ this.encode(this.clientAddress || ''),
].join('-');
}
diff --git a/src/trace/context/ContextManager.ts b/src/trace/context/ContextManager.ts
index e49bbb0..538a6d1 100644
--- a/src/trace/context/ContextManager.ts
+++ b/src/trace/context/ContextManager.ts
@@ -19,25 +19,17 @@
import Context from '../../trace/context/Context';
import SpanContext from '../../trace/context/SpanContext';
-import { executionAsyncId, createHook } from 'async_hooks';
+import { AsyncLocalStorage } from 'async_hooks';
+
+const store = new AsyncLocalStorage<Context>();
class ContextManager {
- contextKeyedByAsyncId: { [asyncId: number]: Context } = {};
-
- constructor() {
- createHook({
- destroy: (asyncId: number) => {
- delete this.contextKeyedByAsyncId[asyncId];
- },
- }).enable();
+ get current(): Context {
+ return store.getStore() || new SpanContext();
}
- get current(): Context {
- const thisAsyncId = executionAsyncId();
-
- this.contextKeyedByAsyncId[thisAsyncId] = this.contextKeyedByAsyncId[thisAsyncId] || new SpanContext(thisAsyncId);
-
- return this.contextKeyedByAsyncId[thisAsyncId];
+ withContext(callback: (...args: any[]) => void, ...args: any[]) {
+ return store.run(new SpanContext(), callback);
}
}
diff --git a/src/trace/context/DummyContext.ts b/src/trace/context/DummyContext.ts
index 54a98e8..e7fc720 100644
--- a/src/trace/context/DummyContext.ts
+++ b/src/trace/context/DummyContext.ts
@@ -73,6 +73,14 @@
}
restore(snapshot: Snapshot) {
- // Big Bang ~
+ return;
+ }
+
+ async(span: Span) {
+ return;
+ }
+
+ await(span: Span) {
+ return;
}
}
diff --git a/src/trace/context/Segment.ts b/src/trace/context/Segment.ts
index 8d9346c..9c8a7fd 100644
--- a/src/trace/context/Segment.ts
+++ b/src/trace/context/Segment.ts
@@ -25,7 +25,6 @@
export default class Segment {
segmentId = new ID();
spans: Span[] = [];
- timestamp: number = 0;
relatedTraces: ID[] = [new NewID()];
references: SegmentRef[] = [];
diff --git a/src/trace/context/SpanContext.ts b/src/trace/context/SpanContext.ts
index d7c53b0..b4e4d3c 100644
--- a/src/trace/context/SpanContext.ts
+++ b/src/trace/context/SpanContext.ts
@@ -23,7 +23,6 @@
import EntrySpan from '../../trace/span/EntrySpan';
import ExitSpan from '../../trace/span/ExitSpan';
import LocalSpan from '../../trace/span/LocalSpan';
-import * as packageInfo from '../../../package.json';
import buffer from '../../agent/Buffer';
import { createLogger } from '../../logging';
import { executionAsyncId } from 'async_hooks';
@@ -37,8 +36,7 @@
spanId = 0;
spans: Span[] = [];
segment: Segment = new Segment();
-
- constructor(public asyncId: number) {}
+ asyncCount: number = 0;
get parent(): Span | null {
if (this.spans.length > 0) {
@@ -117,20 +115,15 @@
stop(span: Span): boolean {
logger.info('Stopping span', { span, spans: this.spans });
- if (this.spans[this.spans.length - 1] !== span) {
- logger.error(`Stopping unexpected span. Consider report this to ${packageInfo.bugs.url}`);
- return true;
- }
-
if (this.tryFinish(span)) {
- this.spans.splice(0, 1);
+ this.spans.splice(this.spans.length - 1, 1);
}
- return this.spans.length === 0;
+ return this.asyncCount === 0 && this.spans.length === 0;
}
tryFinish(span: Span): boolean {
- if (span.finish(this.segment)) {
+ if (span.finish(this.segment) && !span.isAsync) {
if (logger.isDebugEnabled()) {
logger.debug('Finishing span', { span });
}
@@ -159,4 +152,13 @@
this.currentSpan()?.refer(ref);
this.segment.relate(ref.traceId);
}
+
+ async(span: Span) {
+ this.asyncCount++;
+ this.spans.splice(this.spans.indexOf(span), 1);
+ }
+
+ await(span: Span) {
+ this.asyncCount--;
+ }
}
diff --git a/src/trace/span/Span.ts b/src/trace/span/Span.ts
index decfcf3..1ad868e 100644
--- a/src/trace/span/Span.ts
+++ b/src/trace/span/Span.ts
@@ -59,6 +59,8 @@
endTime = 0;
errored = false;
+ _async = false;
+
constructor(options: SpanCtorOptions & { type: SpanType }) {
this.context = options.context;
this.operation = options.operation;
@@ -94,7 +96,7 @@
// noinspection JSUnusedLocalSymbols
extract(): ContextCarrier {
throw new Error(`
- can only inject context carrier into ExitSpan, this may be a potential bug in the agent,
+ can only extract context carrier into ExitSpan, this may be a potential bug in the agent,
please report this in ${packageInfo.bugs.url} if you encounter this.
`);
}
@@ -141,4 +143,20 @@
}
return this;
}
+
+ async(): this {
+ this._async = true;
+ this.context.async(this);
+ return this;
+ }
+
+ await(): this {
+ this._async = false;
+ this.context.await(this);
+ return this;
+ }
+
+ get isAsync(): boolean {
+ return this._async;
+ }
}
diff --git a/tests/plugins/common/Dockerfile.agent b/tests/plugins/common/Dockerfile.agent
index 0722c25..b81f372 100644
--- a/tests/plugins/common/Dockerfile.agent
+++ b/tests/plugins/common/Dockerfile.agent
@@ -13,7 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FROM nodejs-dependencies
+FROM node:12
ARG ROOT=.
@@ -21,4 +21,5 @@
ADD $ROOT /app
-RUN cp -R /dependencies/node_modules /app/
+RUN npm install
+
diff --git a/tests/plugins/http/client.ts b/tests/plugins/http/client.ts
new file mode 100644
index 0000000..bc01846
--- /dev/null
+++ b/tests/plugins/http/client.ts
@@ -0,0 +1,38 @@
+/*!
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import * as http from 'http';
+import Agent from '../../../src';
+
+Agent.start({
+ serviceName: 'client',
+ maxBufferSize: 1000,
+});
+
+http
+ .request('http://localhost:5000', (res) => {
+ let data = '';
+ res.on('data', (chunk) => (data += chunk));
+ res.on('end', () => console.info(data));
+ })
+ .end();
+
+setTimeout(() => {
+ console.info();
+}, 3000);
diff --git a/tests/plugins/http/server.ts b/tests/plugins/http/server.ts
new file mode 100644
index 0000000..2885c56
--- /dev/null
+++ b/tests/plugins/http/server.ts
@@ -0,0 +1,46 @@
+/*!
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import Agent from '../../../src';
+import * as http from 'http';
+
+Agent.start({
+ serviceName: 'server',
+ maxBufferSize: 1000,
+});
+
+const server = http.createServer((req, res) => {
+ http
+ .request('http://httpbin.org/json', (r) => {
+ let data = '';
+ r.on('data', (chunk) => (data += chunk));
+ r.on('end', () => setImmediate(() => res.write(data)));
+ })
+ .end();
+
+ http
+ .request('http://httpbin.org/xml', async (r) => {
+ let data = '';
+ r.on('data', (chunk) => (data += chunk));
+ r.on('end', () => setTimeout(() => res.end(data), 1000));
+ })
+ .end();
+});
+
+server.listen(5000, () => console.info('Listening on port 5000...'));
diff --git a/tests/plugins/http/test.ts b/tests/plugins/http/test.ts
index 00e44ce..3e9770e 100644
--- a/tests/plugins/http/test.ts
+++ b/tests/plugins/http/test.ts
@@ -25,7 +25,7 @@
describe('', () => {
before(function () {
- this.timeout(10_000);
+ this.timeout(60_000);
return setUp(composeFile, () => true);
});
@@ -37,7 +37,7 @@
});
it(`test ${__dirname}`, function (done) {
- this.timeout(10_000);
+ this.timeout(60_000);
done();
});
diff --git a/tests/tsconfig.json b/tests/tsconfig.json
new file mode 100644
index 0000000..e73078b
--- /dev/null
+++ b/tests/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "strict": true,
+ "importHelpers": true,
+ "moduleResolution": "node",
+ "experimentalDecorators": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "rootDir": "..",
+ "baseUrl": "..",
+ "resolveJsonModule": true,
+ "declaration": true,
+ "allowJs": true,
+ "sourceMap": true
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
index 0afd6e6..f6ebc11 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,9 +5,14 @@
"baseUrl": ".",
"outDir": ".",
"resolveJsonModule": true,
- "composite": true
+ "composite": true,
+ "esModuleInterop": true
},
"files": [
"package.json"
+ ],
+ "include": [
+ "src/**/*",
+ "tests/**/*"
]
}