@opencensus/instrumentation-http
Advanced tools
Comparing version 0.0.9 to 0.0.10
@@ -17,7 +17,7 @@ /** | ||
/// <reference types="node" /> | ||
import { BasePlugin, Func } from '@opencensus/core'; | ||
import * as httpModule from 'http'; | ||
import { HttpPluginConfig, IgnoreMatcher } from './types'; | ||
export declare type HttpModule = typeof httpModule; | ||
export declare type RequestFunction = typeof httpModule.request; | ||
import { BasePlugin, Func, SpanKind, TagMap } from '@opencensus/core'; | ||
import { ClientRequest, IncomingMessage, request } from 'http'; | ||
import { IgnoreMatcher } from './types'; | ||
export declare type HttpGetCallback = (res: IncomingMessage) => void; | ||
export declare type RequestFunction = typeof request; | ||
/** Http instrumentation plugin for Opencensus */ | ||
@@ -37,8 +37,5 @@ export declare class HttpPlugin extends BasePlugin { | ||
static ATTRIBUTE_HTTP_ERROR_MESSAGE: string; | ||
protected options: HttpPluginConfig; | ||
/** Constructs a new HttpPlugin instance. */ | ||
constructor(moduleName: string); | ||
/** | ||
* Patches HTTP incoming and outcoming request functions. | ||
*/ | ||
/** Patches HTTP incoming and outcoming request functions. */ | ||
protected applyPatch(): any; | ||
@@ -69,3 +66,3 @@ /** Unpatches all HTTP patched function. */ | ||
*/ | ||
protected getPatchOutgoingRequestFunction(): (original: Func<httpModule.ClientRequest>) => Func<httpModule.ClientRequest>; | ||
protected getPatchOutgoingRequestFunction(): (original: Func<ClientRequest>) => Func<ClientRequest>; | ||
/** | ||
@@ -83,4 +80,6 @@ * Injects span's context to header for distributed tracing and finshes the | ||
static parseResponseStatus(statusCode: number): number; | ||
/** Method to record stats for client and server. */ | ||
static recordStats(kind: SpanKind, tags: TagMap, ms: number): void; | ||
} | ||
declare const plugin: HttpPlugin; | ||
export { plugin }; |
@@ -19,6 +19,14 @@ "use strict"; | ||
const core_1 = require("@opencensus/core"); | ||
const http_1 = require("http"); | ||
const semver = require("semver"); | ||
const shimmer = require("shimmer"); | ||
const url = require("url"); | ||
const uuid = require("uuid"); | ||
const stats = require("./http-stats"); | ||
function isOpenCensusRequest(options) { | ||
return options && options.headers && | ||
!!options.headers['x-opencensus-outgoing-request']; | ||
} | ||
const UNLIMITED_PROPAGATION_MD = { | ||
tagTtl: core_1.TagTtl.UNLIMITED_PROPAGATION | ||
}; | ||
/** Http instrumentation plugin for Opencensus */ | ||
@@ -30,5 +38,3 @@ class HttpPlugin extends core_1.BasePlugin { | ||
} | ||
/** | ||
* Patches HTTP incoming and outcoming request functions. | ||
*/ | ||
/** Patches HTTP incoming and outcoming request functions. */ | ||
applyPatch() { | ||
@@ -40,3 +46,19 @@ this.logger.debug('applying patch to %s@%s', this.moduleName, this.version); | ||
if (semver.satisfies(this.version, '>=8.0.0')) { | ||
shimmer.wrap(this.moduleExports, 'get', this.getPatchOutgoingRequestFunction()); | ||
shimmer.wrap(this.moduleExports, 'get', () => { | ||
// Re-implement http.get. This needs to be done (instead of using | ||
// getPatchOutgoingRequestFunction to patch it) because we need to | ||
// set the trace context header before the returned ClientRequest is | ||
// ended. The Node.js docs state that the only differences between | ||
// request and get are that (1) get defaults to the HTTP GET method and | ||
// (2) the returned request object is ended immediately. The former is | ||
// already true (at least in supported Node versions up to v9), so we | ||
// simply follow the latter. Ref: | ||
// https://nodejs.org/dist/latest/docs/api/http.html#http_http_get_options_callback | ||
// https://github.com/googleapis/cloud-trace-nodejs/blob/master/src/plugins/plugin-http.ts#L198 | ||
return function getTrace(options, callback) { | ||
const req = http_1.request(options, callback); | ||
req.end(); | ||
return req; | ||
}; | ||
}); | ||
} | ||
@@ -115,5 +137,7 @@ if (this.moduleExports && this.moduleExports.Server && | ||
} | ||
const startTime = Date.now(); | ||
const request = args[0]; | ||
const response = args[1]; | ||
const path = url.parse(request.url).pathname; | ||
const path = request.url ? url.parse(request.url).pathname || '' : ''; | ||
const method = request.method || 'GET'; | ||
plugin.logger.debug('%s plugin incomingRequest', plugin.moduleName); | ||
@@ -130,7 +154,9 @@ if (plugin.isIgnored(path, request, plugin.options.ignoreIncomingPaths)) { | ||
}; | ||
const traceOptions = { | ||
name: path, | ||
kind: core_1.SpanKind.SERVER, | ||
spanContext: propagation ? propagation.extract(getter) : null | ||
}; | ||
const traceOptions = { name: path, kind: core_1.SpanKind.SERVER }; | ||
if (propagation) { | ||
const spanContext = propagation.extract(getter); | ||
if (spanContext) { | ||
traceOptions.spanContext = spanContext; | ||
} | ||
} | ||
return plugin.tracer.startRootSpan(traceOptions, rootSpan => { | ||
@@ -147,14 +173,22 @@ if (!rootSpan) | ||
const returned = response.end.apply(this, arguments); | ||
const requestUrl = url.parse(request.url); | ||
const requestUrl = request.url ? url.parse(request.url) : null; | ||
const host = headers.host || 'localhost'; | ||
const userAgent = (headers['user-agent'] || headers['User-Agent']); | ||
const tags = new core_1.TagMap(); | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_HOST, host.replace(/^(.*)(\:[0-9]{1,5})/, '$1')); | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_METHOD, request.method); | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_PATH, requestUrl.pathname); | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ROUTE, requestUrl.path); | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT, userAgent); | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_METHOD, method); | ||
if (requestUrl) { | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_PATH, requestUrl.pathname || ''); | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ROUTE, requestUrl.path || ''); | ||
tags.set(stats.HTTP_SERVER_ROUTE, { value: requestUrl.path || '' }, UNLIMITED_PROPAGATION_MD); | ||
} | ||
if (userAgent) { | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT, userAgent); | ||
} | ||
rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE, response.statusCode.toString()); | ||
rootSpan.setStatus(HttpPlugin.parseResponseStatus(response.statusCode)); | ||
// Message Event ID is not defined | ||
rootSpan.addMessageEvent(core_1.MessageEventType.RECEIVED, uuid.v4().split('-').join('')); | ||
rootSpan.addMessageEvent(core_1.MessageEventType.RECEIVED, 1); | ||
tags.set(stats.HTTP_SERVER_METHOD, { value: method }, UNLIMITED_PROPAGATION_MD); | ||
tags.set(stats.HTTP_SERVER_STATUS, { value: response.statusCode.toString() }, UNLIMITED_PROPAGATION_MD); | ||
HttpPlugin.recordStats(rootSpan.kind, tags, Date.now() - startTime); | ||
rootSpan.end(); | ||
@@ -177,7 +211,7 @@ return returned; | ||
if (!options) { | ||
return original.apply(this, arguments); | ||
return original.apply(this, [options, callback]); | ||
} | ||
// Makes sure the url is an url object | ||
let pathname = ''; | ||
let method = 'GET'; | ||
let pathname; | ||
let method; | ||
let origin = ''; | ||
@@ -187,3 +221,3 @@ if (typeof (options) === 'string') { | ||
options = parsedUrl; | ||
pathname = parsedUrl.pathname; | ||
pathname = parsedUrl.pathname || ''; | ||
origin = `${parsedUrl.protocol || 'http:'}//${parsedUrl.host}`; | ||
@@ -193,17 +227,18 @@ } | ||
// Do not trace ourselves | ||
if (options.headers && | ||
options.headers['x-opencensus-outgoing-request']) { | ||
if (isOpenCensusRequest(options)) { | ||
plugin.logger.debug('header with "x-opencensus-outgoing-request" - do not trace'); | ||
return original.apply(this, arguments); | ||
return original.apply(this, [options, callback]); | ||
} | ||
try { | ||
pathname = options.pathname || | ||
url.parse(options.path).pathname; | ||
method = options.method; | ||
pathname = options.pathname; | ||
if (!pathname) { | ||
pathname = options.path ? url.parse(options.path).pathname : ''; | ||
} | ||
method = options.method || 'GET'; | ||
origin = `${options.protocol || 'http:'}//${options.host}`; | ||
} | ||
catch (e) { | ||
catch (ignore) { | ||
} | ||
} | ||
const request = original.apply(this, arguments); | ||
const request = original.apply(this, [options, callback]); | ||
if (plugin.isIgnored(origin + pathname, request, plugin.options.ignoreOutgoingUrls)) { | ||
@@ -240,6 +275,5 @@ return request; | ||
*/ | ||
getMakeRequestTraceFunction( | ||
// tslint:disable-next-line:no-any | ||
request, options, plugin) { | ||
getMakeRequestTraceFunction(request, options, plugin) { | ||
return (span) => { | ||
const startTime = Date.now(); | ||
plugin.logger.debug('makeRequestTrace'); | ||
@@ -267,13 +301,21 @@ if (!span) { | ||
const userAgent = headers ? (headers['user-agent'] || headers['User-Agent']) : null; | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_HOST, options.hostname); | ||
const tags = new core_1.TagMap(); | ||
tags.set(stats.HTTP_CLIENT_METHOD, { value: method }); | ||
const host = options.hostname || options.host || 'localhost'; | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_HOST, host); | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_METHOD, method); | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_PATH, options.path); | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ROUTE, options.path); | ||
if (options.path) { | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_PATH, options.path); | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ROUTE, options.path); | ||
} | ||
if (userAgent) { | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT, userAgent.toString()); | ||
} | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE, response.statusCode.toString()); | ||
span.setStatus(HttpPlugin.parseResponseStatus(response.statusCode)); | ||
// Message Event ID is not defined | ||
span.addMessageEvent(core_1.MessageEventType.SENT, uuid.v4().split('-').join('')); | ||
if (response.statusCode) { | ||
span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE, response.statusCode.toString()); | ||
span.setStatus(HttpPlugin.parseResponseStatus(response.statusCode)); | ||
tags.set(stats.HTTP_CLIENT_STATUS, { value: response.statusCode.toString() }); | ||
} | ||
span.addMessageEvent(core_1.MessageEventType.SENT, 1); | ||
HttpPlugin.recordStats(span.kind, tags, Date.now() - startTime); | ||
span.end(); | ||
@@ -332,2 +374,23 @@ }); | ||
} | ||
/** Method to record stats for client and server. */ | ||
static recordStats(kind, tags, ms) { | ||
if (!plugin.stats) | ||
return; | ||
try { | ||
const measureList = []; | ||
switch (kind) { | ||
case core_1.SpanKind.CLIENT: | ||
measureList.push({ measure: stats.HTTP_CLIENT_ROUNDTRIP_LATENCY, value: ms }); | ||
break; | ||
case core_1.SpanKind.SERVER: | ||
measureList.push({ measure: stats.HTTP_SERVER_LATENCY, value: ms }); | ||
break; | ||
default: | ||
break; | ||
} | ||
plugin.stats.record(measureList, tags); | ||
} | ||
catch (ignore) { | ||
} | ||
} | ||
} | ||
@@ -334,0 +397,0 @@ /** |
@@ -17,1 +17,2 @@ /** | ||
export * from './http'; | ||
export { registerAllClientViews, registerAllServerViews, registerAllViews } from './http-stats'; |
@@ -22,2 +22,6 @@ "use strict"; | ||
__export(require("./http")); | ||
var http_stats_1 = require("./http-stats"); | ||
exports.registerAllClientViews = http_stats_1.registerAllClientViews; | ||
exports.registerAllServerViews = http_stats_1.registerAllServerViews; | ||
exports.registerAllViews = http_stats_1.registerAllViews; | ||
//# sourceMappingURL=index.js.map |
@@ -0,1 +1,16 @@ | ||
/** | ||
* Copyright 2018, OpenCensus Authors | ||
* | ||
* Licensed 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. | ||
*/ | ||
/// <reference types="node" /> | ||
@@ -2,0 +17,0 @@ import { ClientRequest, IncomingMessage } from 'http'; |
"use strict"; | ||
/** | ||
* Copyright 2018, OpenCensus Authors | ||
* | ||
* Licensed 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. | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
//# sourceMappingURL=types.js.map |
{ | ||
"name": "@opencensus/instrumentation-http", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"description": "Opencensus http automatic instrumentation package.", | ||
@@ -9,3 +9,3 @@ "main": "build/src/index.js", | ||
"scripts": { | ||
"test": "nyc mocha build/test/**/*.js", | ||
"test": "nyc ts-mocha -p ./tsconfig.json test/**/*.ts", | ||
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json", | ||
@@ -17,3 +17,2 @@ "clean": "rimraf build/*", | ||
"prepare": "npm run compile", | ||
"pretest": "npm run compile", | ||
"posttest": "npm run check" | ||
@@ -40,2 +39,13 @@ }, | ||
], | ||
"nyc": { | ||
"extension": [ | ||
".ts", | ||
".tsx" | ||
], | ||
"exclude": [ | ||
"**/*.d.ts", | ||
"build/**/**/*.js" | ||
], | ||
"all": true | ||
}, | ||
"publishConfig": { | ||
@@ -45,26 +55,22 @@ "access": "public" | ||
"devDependencies": { | ||
"@types/end-of-stream": "^1.4.0", | ||
"@types/mocha": "^5.2.5", | ||
"@types/nock": "^9.1.3", | ||
"@types/node": "^9.4.7", | ||
"@types/semver": "^5.5.0", | ||
"@types/semver": "^6.0.0", | ||
"@types/shimmer": "^1.0.1", | ||
"@types/uuid": "^3.4.3", | ||
"codecov": "^3.1.0", | ||
"gts": "^0.9.0", | ||
"mocha": "^5.0.4", | ||
"ncp": "^2.0.0", | ||
"mocha": "^6.0.0", | ||
"nock": "^10.0.0", | ||
"nyc": "^13.0.0", | ||
"rimraf": "^2.6.2", | ||
"ts-node": "^7.0.1", | ||
"ts-mocha": "^6.0.0", | ||
"ts-node": "^8.0.0", | ||
"typescript": "~2.9.0" | ||
}, | ||
"dependencies": { | ||
"@opencensus/core": "^0.0.9", | ||
"end-of-stream": "^1.4.1", | ||
"semver": "^5.5.0", | ||
"shimmer": "^1.2.0", | ||
"uuid": "^3.2.1" | ||
"@opencensus/core": "^0.0.10", | ||
"semver": "^6.0.0", | ||
"shimmer": "^1.2.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
53750
3
14
11
857
1
+ Added@opencensus/core@0.0.10(transitive)
+ Addedsemver@6.3.1(transitive)
- Removedend-of-stream@^1.4.1
- Removeduuid@^3.2.1
- Removed@opencensus/core@0.0.9(transitive)
- Removedend-of-stream@1.4.4(transitive)
- Removedonce@1.4.0(transitive)
- Removedwrappy@1.0.2(transitive)
Updated@opencensus/core@^0.0.10
Updatedsemver@^6.0.0