diff --git a/package-lock.json b/package-lock.json index 0a8c28b..5cdcf75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -516,6 +516,31 @@ "minimist": "^1.2.0" } }, + "@grpc/grpc-js": { + "version": "1.2.3", + "resolved": "http://npm.meshkit.cn/@grpc%2fgrpc-js/-/grpc-js-1.2.3.tgz", + "integrity": "sha1-Ndy8o8t0Fe9axuc9RAgOvLRKS+U=", + "dev": true, + "requires": { + "@types/node": "^12.12.47", + "google-auth-library": "^6.1.1", + "semver": "^6.2.0" + }, + "dependencies": { + "@types/node": { + "version": "12.19.13", + "resolved": "http://npm.meshkit.cn/@types%2fnode/-/node-12.19.13.tgz", + "integrity": "sha1-iI4rNBWfuRSWWJSE7BaWGCErUbc=", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "http://npm.meshkit.cn/semver/-/semver-6.3.0.tgz", + "integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=", + "dev": true + } + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npm.taobao.org/@istanbuljs/load-nyc-config/download/@istanbuljs/load-nyc-config-1.1.0.tgz", @@ -1282,6 +1307,15 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, + "abort-controller": { + "version": "3.0.0", + "resolved": "http://npm.meshkit.cn/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha1-6vVNU7YrrkE46AnKIlyEOabvs5I=", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, "accepts": { "version": "1.3.7", "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", @@ -1314,6 +1348,26 @@ "integrity": "sha1-DeiJpgEgOQmw++B7iTjcIdLpZ7w=", "dev": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "http://npm.meshkit.cn/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha1-Sf/1hXfP7j83F2/qtMIuAPhtf3c=", + "dev": true, + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "http://npm.meshkit.cn/debug/-/debug-4.3.1.tgz", + "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", + "dev": true, + "requires": { + "ms": "2.1.2" + } + } + } + }, "ansi-bgblack": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz", @@ -1715,6 +1769,12 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "arrify": { + "version": "2.0.1", + "resolved": "http://npm.meshkit.cn/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo=", + "dev": true + }, "ascli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz", @@ -1928,6 +1988,12 @@ "tweetnacl": "^0.14.3" } }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "http://npm.meshkit.cn/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha1-jXuhJMiCv9jkMmDGdHVRjQaJ5OU=", + "dev": true + }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npm.taobao.org/body-parser/download/body-parser-1.19.0.tgz", @@ -2030,6 +2096,12 @@ "ieee754": "^1.1.13" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "http://npm.meshkit.cn/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", + "dev": true + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -2615,6 +2687,12 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, + "denque": { + "version": "1.5.0", + "resolved": "http://npm.meshkit.cn/denque/-/denque-1.5.0.tgz", + "integrity": "sha1-dz3gaG/y2Owv+SkUMWpHtzscc94=", + "dev": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", @@ -2751,6 +2829,15 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "http://npm.meshkit.cn/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha1-rg8PothQRe8UqBfao86azQSJ5b8=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", @@ -2875,6 +2962,12 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "http://npm.meshkit.cn/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha1-XU0+vflYPWOlMzzi3rdICrKwV4k=", + "dev": true + }, "exec-sh": { "version": "0.3.4", "resolved": "https://registry.npm.taobao.org/exec-sh/download/exec-sh-0.3.4.tgz", @@ -3095,6 +3188,12 @@ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" }, + "fast-text-encoding": { + "version": "1.0.3", + "resolved": "http://npm.meshkit.cn/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha1-7AKsjgGrijGa8YLa4mgSE8/pzlM=", + "dev": true + }, "fb-watchman": { "version": "2.0.1", "resolved": "https://registry.npm.taobao.org/fb-watchman/download/fb-watchman-2.0.1.tgz", @@ -3295,6 +3394,46 @@ "wide-align": "^1.1.0" } }, + "gaxios": { + "version": "4.1.0", + "resolved": "http://npm.meshkit.cn/gaxios/-/gaxios-4.1.0.tgz", + "integrity": "sha1-6K1GbbWkODxwudY7/RTfqofrAJk=", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + }, + "dependencies": { + "is-stream": { + "version": "2.0.0", + "resolved": "http://npm.meshkit.cn/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha1-venDJoDW+uBBKdasnZIc54FfeOM=", + "dev": true + } + } + }, + "gcp-metadata": { + "version": "4.2.1", + "resolved": "http://npm.meshkit.cn/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha1-MYSfvPkCXvNMIpfDKomh5+nyzWI=", + "dev": true, + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "generate-function": { + "version": "2.3.1", + "resolved": "http://npm.meshkit.cn/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha1-8GlhdpDBDIaOc7hGV0Z2T5fDR58=", + "dev": true, + "requires": { + "is-property": "^1.0.2" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npm.taobao.org/gensync/download/gensync-1.0.0-beta.2.tgz?cache=0&sync_timestamp=1603829637456&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fgensync%2Fdownload%2Fgensync-1.0.0-beta.2.tgz", @@ -3398,6 +3537,32 @@ "integrity": "sha1-q4eVM4hooLq9hSV1gBjCp+uVxC4=", "dev": true }, + "google-auth-library": { + "version": "6.1.4", + "resolved": "http://npm.meshkit.cn/google-auth-library/-/google-auth-library-6.1.4.tgz", + "integrity": "sha1-vHDE87ZoGuUnM0NGa87zdXe37kQ=", + "dev": true, + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "http://npm.meshkit.cn/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha1-ZzrDp105A6h/BYePPHXgb8FRZp4=", + "dev": true, + "requires": { + "node-forge": "^0.10.0" + } + }, "google-protobuf": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.14.0.tgz", @@ -3457,6 +3622,26 @@ } } }, + "gtoken": { + "version": "5.1.0", + "resolved": "http://npm.meshkit.cn/gtoken/-/gtoken-5.1.0.tgz", + "integrity": "sha1-S6jS/JqEWQmPdufo/Xvqo5/an+Q=", + "dev": true, + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0", + "mime": "^2.2.0" + }, + "dependencies": { + "mime": { + "version": "2.4.7", + "resolved": "http://npm.meshkit.cn/mime/-/mime-2.4.7.tgz", + "integrity": "sha1-lirtm+DtGckf19wuzl1/TompDXQ=", + "dev": true + } + } + }, "gulp-header": { "version": "1.8.12", "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz", @@ -3822,6 +4007,27 @@ "sshpk": "^1.7.0" } }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "http://npm.meshkit.cn/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha1-4qkFQqu2inYuCghQ9sntrf2FBrI=", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "http://npm.meshkit.cn/debug/-/debug-4.3.1.tgz", + "integrity": "sha1-8NIpxQXgxtjEmsVT0bE9wYP2su4=", + "dev": true, + "requires": { + "ms": "2.1.2" + } + } + } + }, "human-signals": { "version": "1.1.1", "resolved": "https://registry.npm.taobao.org/human-signals/download/human-signals-1.1.1.tgz", @@ -4097,6 +4303,12 @@ "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", "dev": true }, + "is-property": { + "version": "1.0.2", + "resolved": "http://npm.meshkit.cn/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, "is-self-closing": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-self-closing/-/is-self-closing-1.0.1.tgz", @@ -5553,6 +5765,15 @@ "integrity": "sha1-gFZNLkg9rPbo7yCWUKZ98/DCg6Q=", "dev": true }, + "json-bigint": { + "version": "1.0.0", + "resolved": "http://npm.meshkit.cn/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha1-rlR4I6wMrYOYZn+M2e9HMPWwH/E=", + "dev": true, + "requires": { + "bignumber.js": "^9.0.0" + } + }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npm.taobao.org/json-parse-even-better-errors/download/json-parse-even-better-errors-2.3.1.tgz", @@ -5598,6 +5819,27 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "2.0.0", + "resolved": "http://npm.meshkit.cn/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha1-p+nD8p2ulAJ+vK9Jl1yTRVk0EPw=", + "dev": true, + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "http://npm.meshkit.cn/jws/-/jws-4.0.0.tgz", + "integrity": "sha1-LU6M9qMY/6oSYV6d7H6G5slzEPQ=", + "dev": true, + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -5770,6 +6012,23 @@ "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" }, + "lru-cache": { + "version": "6.0.0", + "resolved": "http://npm.meshkit.cn/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "http://npm.meshkit.cn/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", + "dev": true + } + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npm.taobao.org/make-dir/download/make-dir-3.1.0.tgz", @@ -6025,6 +6284,66 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "mysql2": { + "version": "2.2.5", + "resolved": "http://npm.meshkit.cn/mysql2/-/mysql2-2.2.5.tgz", + "integrity": "sha1-cmJP+0gW+A+Wucl/7djACTX580A=", + "dev": true, + "requires": { + "denque": "^1.4.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.2", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.2", + "resolved": "http://npm.meshkit.cn/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha1-zhPRh1sMOmdL1qBLf3awGxtt7QE=", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "long": { + "version": "4.0.0", + "resolved": "http://npm.meshkit.cn/long/-/long-4.0.0.tgz", + "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=", + "dev": true + } + } + }, + "named-placeholders": { + "version": "1.1.2", + "resolved": "http://npm.meshkit.cn/named-placeholders/-/named-placeholders-1.1.2.tgz", + "integrity": "sha1-zrH7/1C2szSStc8hTM9eOc7z0Og=", + "dev": true, + "requires": { + "lru-cache": "^4.1.3" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "http://npm.meshkit.cn/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha1-i75Q6oW+1ZvJ4z3KuCNe6bz0Q80=", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "http://npm.meshkit.cn/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, "nan": { "version": "2.14.1", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", @@ -6143,6 +6462,18 @@ "integrity": "sha1-ozeKdpbOfSI+iPybdkvX7xCJ42Y=", "dev": true }, + "node-fetch": { + "version": "2.6.1", + "resolved": "http://npm.meshkit.cn/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha1-BFvTI2Mfdu0uK1VXM5RBa2OaAFI=", + "dev": true + }, + "node-forge": { + "version": "0.10.0", + "resolved": "http://npm.meshkit.cn/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha1-Mt6ir7Ppkm8C7lzoeUkCaRpna/M=", + "dev": true + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npm.taobao.org/node-int64/download/node-int64-0.4.0.tgz", @@ -6628,6 +6959,12 @@ "ipaddr.js": "1.9.1" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "http://npm.meshkit.cn/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npm.taobao.org/psl/download/psl-1.8.0.tgz", @@ -7093,6 +7430,12 @@ } } }, + "seq-queue": { + "version": "0.0.5", + "resolved": "http://npm.meshkit.cn/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=", + "dev": true + }, "serve-static": { "version": "1.14.1", "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.14.1.tgz", @@ -7372,6 +7715,12 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sqlstring": { + "version": "2.3.2", + "resolved": "http://npm.meshkit.cn/sqlstring/-/sqlstring-2.3.2.tgz", + "integrity": "sha1-za5xaTiaE3WxjohfLmCz5GCAlRQ=", + "dev": true + }, "ssh-remote-port-forward": { "version": "1.0.3", "resolved": "https://registry.npm.taobao.org/ssh-remote-port-forward/download/ssh-remote-port-forward-1.0.3.tgz", diff --git a/package.json b/package.json index 4409c2b..64cd72d 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "email": "dev@skywalking.apache.org" }, "devDependencies": { + "@grpc/grpc-js": "^1.2.3", "@types/express": "^4.17.9", "@types/google-protobuf": "^3.7.2", "@types/jest": "^26.0.15", @@ -49,6 +50,7 @@ "grpc-tools": "^1.10.0", "grpc_tools_node_protoc_ts": "^4.0.0", "jest": "^26.6.3", + "mysql2": "^2.2.5", "prettier": "^2.0.5", "testcontainers": "^6.2.0", "ts-jest": "^26.4.4", diff --git a/src/Tag.ts b/src/Tag.ts index 229fea4..7e7086b 100644 --- a/src/Tag.ts +++ b/src/Tag.ts @@ -45,4 +45,39 @@ export default { val: `${val}`, } as Tag; }, + DBType: (val: string | undefined): Tag => { + return { + key: 'db.type', + overridable: true, + val: `${val}`, + }; + }, + DBInstance: (val: string | undefined): Tag => { + return { + key: 'db.instance', + overridable: true, + val: `${val}`, + }; + }, + DBStatement: (val: string | undefined): Tag => { + return { + key: 'db.statement', + overridable: true, + val: `${val}`, + }; + }, + GrpcMetaData: (val: string | undefined): Tag => { + return { + key: 'grpc.metadata', + overridable: true, + val: `${val}`, + }; + }, + GrpcArgument: (val: string | undefined): Tag => { + return { + key: 'grpc.argument', + overridable: true, + val: `${val}`, + }; + }, }; diff --git a/src/plugins/GrpcPlugin.ts b/src/plugins/GrpcPlugin.ts new file mode 100644 index 0000000..b6108c1 --- /dev/null +++ b/src/plugins/GrpcPlugin.ts @@ -0,0 +1,144 @@ +import { CallOptions, Metadata, ServiceDefinition } from "@grpc/grpc-js"; +import { SpanLayer } from "../proto/language-agent/Tracing_pb"; +import { Component } from "../trace/Component"; +import SwPlugin from "../core/SwPlugin"; +import ContextManager from "../trace/context/ContextManager"; +import Tag from "../Tag"; +import { ServerSurfaceCall } from "@grpc/grpc-js/build/src/server-call"; +import { ContextCarrier } from "../trace/context/ContextCarrier"; +import PluginInstaller from "../core/PluginInstaller"; + +class GrpcPlugin implements SwPlugin { + readonly module = '@grpc/grpc-js'; + readonly versions = '*'; + + install(installer: PluginInstaller): void { + this.interceptClientMakeUnaryRequest(installer); + this.interceptServerCall(installer); + } + + private interceptClientMakeUnaryRequest(installer: PluginInstaller) { + const grpc = installer.require("@grpc/grpc-js") + Object.defineProperty(grpc, "makeClientConstructor", { + value: function (methods: ServiceDefinition, + serviceName: string, + classOptions?: {}) { + const requesterFuncs = { + unary: grpc.Client.prototype.makeUnaryRequest, + server_stream: grpc.Client.prototype.makeServerStreamRequest, + client_stream: grpc.Client.prototype.makeClientStreamRequest, + bidi: grpc.Client.prototype.makeBidiStreamRequest, + }; + function partial(fn: Function, + path: string, + serialize: Function, + deserialize: Function) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return function (this: any, argument: any, metadata: Metadata, options: CallOptions, callback: any) { + const checkedArguments = this.checkOptionalUnaryResponseArguments(metadata, options, callback); + var span = ContextManager.current.newExitSpan(path, this.getChannel().getTarget()).start(); + span.component = Component.GRPC; + span.layer = SpanLayer.RPCFRAMEWORK; + span.tag(Tag.GrpcArgument(JSON.stringify(argument))); + span.inject().items.forEach(item => { + checkedArguments.metadata.set(item.key, item.value); + }) + span.async(); + const emitter = fn.call(this, path, serialize, deserialize, argument, checkedArguments.metadata, checkedArguments.options, checkedArguments.callback); + emitter.on("status", function () { + span.resync(); + span.stop(); + }); + return emitter; + }; + } + if (!classOptions) { + classOptions = {}; + } + class ServiceClientImpl extends grpc.Client { + } + + Object.keys(methods).forEach((name) => { + if (name === '__proto__') { + return; + } + const attrs = methods[name]; + let methodType: keyof typeof requesterFuncs; + // TODO(murgatroid99): Verify that we don't need this anymore + if (typeof name === 'string' && name.charAt(0) === '$') { + throw new Error('Method names cannot start with $'); + } + if (attrs.requestStream) { + if (attrs.responseStream) { + methodType = 'bidi'; + } else { + methodType = 'client_stream'; + } + } else { + if (attrs.responseStream) { + methodType = 'server_stream'; + } else { + methodType = 'unary'; + } + } + const serialize = attrs.requestSerialize; + const deserialize = attrs.responseDeserialize; + const methodFunc = partial( + requesterFuncs[methodType], + attrs.path, + serialize, + deserialize + ); + ServiceClientImpl.prototype[name] = methodFunc; + // Associate all provided attributes with the method + Object.assign(ServiceClientImpl.prototype[name], attrs); + if (attrs.originalName && attrs.originalName !== '__proto__') { + ServiceClientImpl.prototype[attrs.originalName] = + ServiceClientImpl.prototype[name]; + } + }); + + ServiceClientImpl.service = methods; + + return ServiceClientImpl; + } + }) + } + + private interceptServerCall(installer: PluginInstaller) { + const call = installer.require("@grpc/grpc-js/build/src/server-call") + const Http2ServerCallStream = call.Http2ServerCallStream; + // this method called by handleUnary/handleClientStreaming/handleServerStreaming/handleBidiStreaming when create emitter or stream + const setupSurfaceCall: Function = Http2ServerCallStream.prototype.setupSurfaceCall; + Http2ServerCallStream.prototype.setupSurfaceCall = function (call: ServerSurfaceCall) { + const metadata = call.metadata.getMap(); + const headersMap: { [key: string]: string } = {}; + for (const key in metadata) { + headersMap[key] = metadata[key].toString(); + } + const carrier = ContextCarrier.from(headersMap); + const span = ContextManager.current.newEntrySpan(this.handler.path, carrier).start(); + span.component = Component.GRPC; + span.layer = SpanLayer.RPCFRAMEWORK; + const socket = this.stream.session.socket; + let remoteAddress = ""; + if (socket.remoteAddress) { + if (socket.remotePort) { + remoteAddress = `${socket.remoteAddress}:${socket.remotePort}`; + } else { + remoteAddress = socket.remoteAddress; + } + } + span.peer = remoteAddress; + setupSurfaceCall.apply(this, [call]); + } + const sendUnaryMessage: Function = Http2ServerCallStream.prototype.sendUnaryMessage; + Http2ServerCallStream.prototype.sendUnaryMessage = function () { + ContextManager.spans[0].stop(); + sendUnaryMessage.apply(this, arguments); + } + + } +} + +export default new GrpcPlugin(); diff --git a/src/plugins/MysqlPlugin.ts b/src/plugins/MysqlPlugin.ts new file mode 100644 index 0000000..4deae5e --- /dev/null +++ b/src/plugins/MysqlPlugin.ts @@ -0,0 +1,43 @@ +import PluginInstaller from "../core/PluginInstaller"; +import Connection from "mysql2/typings/mysql/lib/Connection"; +import Query from "mysql2/typings/mysql/lib/protocol/sequences/Query"; +import { SpanLayer } from "../proto/language-agent/Tracing_pb"; +import { Component } from "../trace/Component"; +import ContextManager from "../trace/context/ContextManager"; +import SwPlugin from "../core/SwPlugin"; +import Tag from "../Tag"; + +class MysqlPlugin implements SwPlugin { + readonly module = 'mysql2'; + readonly versions = '*'; + + install(installer: PluginInstaller): void { + this.interceptSql(installer); + } + + private interceptSql(installer: PluginInstaller) { + const mysql = installer.require("mysql2"); + const Connection = mysql.Connection; + const _query: Function = Connection.prototype.query; + Connection.prototype.query = function (this: Connection, sql: any, values: any, cb: any) { + const span = ContextManager.current.newExitSpan("Mysql/query", `${this.config.host}:${this.config.port}`).start(); + const query: Query = _query.apply(this, [sql, values, cb]); + span.component = Component.MYSQL; + span.layer = SpanLayer.DATABASE; + span.tag(Tag.DBType("mysql")); + span.tag(Tag.DBInstance(this.config.database ?? "unknown")); + span.tag(Tag.DBStatement(query.sql)); + span.async(); + const _onResult: Function = (query as any).onResult; + (query as any).onResult = function () { + span.resync(); + span.stop(); + _onResult.apply(this, arguments); + } + return query; + } + } + +} + +export default new MysqlPlugin(); diff --git a/src/trace/Component.ts b/src/trace/Component.ts index 1eb9597..6a32bbf 100644 --- a/src/trace/Component.ts +++ b/src/trace/Component.ts @@ -20,10 +20,12 @@ export class Component { static readonly UNKNOWN = new Component(0); static readonly HTTP = new Component(2); + static readonly MYSQL = new Component(5); static readonly MONGODB = new Component(9); + static readonly GRPC = new Component(23); static readonly HTTP_SERVER = new Component(49); static readonly EXPRESS = new Component(4002); static readonly AXIOS = new Component(4005); - constructor(public readonly id: number) {} + constructor(public readonly id: number) { } }