123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- const core_1 = require("@opencensus/core");
- const httpModule = require("http");
- const semver = require("semver");
- const shimmer = require("shimmer");
- const url = require("url");
- const uuid = require("uuid");
- const express_1 = require("./express");
- class HttpPlugin extends core_1.BasePlugin {
- constructor(moduleName) {
- super(moduleName);
- }
- applyPatch() {
- this.logger.debug('applying patch to %s@%s', this.moduleName, this.version);
- shimmer.wrap(this.moduleExports, 'request', this.getPatchOutgoingRequestFunction());
- if (semver.satisfies(this.version, '>=8.0.0')) {
- shimmer.wrap(this.moduleExports, 'get', () => {
- return function getTrace(options, callback) {
- const req = httpModule.request(options, callback);
- req.end();
- return req;
- };
- });
- }
- if (this.moduleExports && this.moduleExports.Server &&
- this.moduleExports.Server.prototype) {
- shimmer.wrap(this.moduleExports.Server.prototype, 'emit', this.getPatchIncomingRequestFunction());
- }
- else {
- this.logger.error('Could not apply patch to %s.emit. Interface is not as expected.', this.moduleName);
- }
- return this.moduleExports;
- }
- applyUnpatch() {
- shimmer.unwrap(this.moduleExports, 'request');
- if (semver.satisfies(this.version, '>=8.0.0')) {
- shimmer.unwrap(this.moduleExports, 'get');
- }
- if (this.moduleExports && this.moduleExports.Server &&
- this.moduleExports.Server.prototype) {
- shimmer.unwrap(this.moduleExports.Server.prototype, 'emit');
- }
- }
- isIgnored(url, request, list) {
- if (!list) {
- return false;
- }
- for (const pattern of list) {
- if (this.isSatisfyPattern(url, request, pattern)) {
- return true;
- }
- }
- return false;
- }
- isSatisfyPattern(url, request, pattern) {
- if (typeof pattern === 'string') {
- return pattern === url;
- }
- else if (pattern instanceof RegExp) {
- return pattern.test(url);
- }
- else if (typeof pattern === 'function') {
- return pattern(url, request);
- }
- else {
- throw new TypeError('Pattern is in unsupported datatype');
- }
- }
- getPatchIncomingRequestFunction() {
- return (original) => {
- const plugin = this;
- return function incomingRequest(event, ...args) {
- if (event !== 'request') {
- return original.apply(this, arguments);
- }
- const request = args[0];
- const response = args[1];
- const path = url.parse(request.url).pathname;
- plugin.logger.debug('%s plugin incomingRequest', plugin.moduleName);
- if (plugin.isIgnored(path, request, plugin.options.ignoreIncomingPaths)) {
- return original.apply(this, arguments);
- }
- const propagation = plugin.tracer.propagation;
- const headers = request.headers;
- const getter = {
- getHeader(name) {
- return headers[name];
- }
- };
- const context = propagation ? propagation.extract(getter) : null;
- const traceOptions = {
- name: path,
- kind: core_1.SpanKind.SERVER,
- spanContext: context !== null ? context : undefined
- };
- return plugin.createSpan(traceOptions, rootSpan => {
- if (!rootSpan)
- return original.apply(this, arguments);
- plugin.tracer.wrapEmitter(request);
- plugin.tracer.wrapEmitter(response);
- const originalEnd = response.end;
- response.end = function () {
- response.end = originalEnd;
- const returned = response.end.apply(this, arguments);
- const requestUrl = url.parse(request.url || 'localhost');
- const host = headers.host || 'localhost';
- const userAgent = (headers['user-agent'] || headers['User-Agent']);
- rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_HOST, host.replace(/^(.*)(\:[0-9]{1,5})/, '$1'));
- rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_METHOD, request.method || 'GET');
- rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_PATH, `${requestUrl.pathname}`);
- let route = `${requestUrl.path}`;
- const middlewareStack = request[express_1.kMiddlewareStack];
- if (middlewareStack) {
- route = middlewareStack
- .filter(path => path !== '/')
- .map(path => {
- return path[0] === '/' ? path : '/' + path;
- }).join('');
- }
- rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ROUTE, route);
- rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT, userAgent);
- rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE, response.statusCode.toString());
- rootSpan.setStatus(HttpPlugin.convertTraceStatus(response.statusCode));
- rootSpan.addMessageEvent(core_1.MessageEventType.RECEIVED, uuid.v4().split('-').join(''));
- rootSpan.end();
- return returned;
- };
- return original.apply(this, arguments);
- });
- };
- };
- }
- getPatchOutgoingRequestFunction() {
- return (original) => {
- const plugin = this;
- const kind = plugin.moduleName === 'https' ? 'HTTPS' : 'HTTP';
- return function outgoingRequest(options, callback) {
- if (!options) {
- return original.apply(this, arguments);
- }
- let pathname = '';
- let method = 'GET';
- let origin = '';
- if (typeof (options) === 'string') {
- const parsedUrl = url.parse(options);
- options = parsedUrl;
- pathname = parsedUrl.pathname || '/';
- origin = `${parsedUrl.protocol || 'http:'}//${parsedUrl.host}`;
- }
- else {
- if (options.headers &&
- options.headers['x-opencensus-outgoing-request']) {
- plugin.logger.debug('header with "x-opencensus-outgoing-request" - do not trace');
- return original.apply(this, arguments);
- }
- try {
- pathname = options.pathname || '';
- if (pathname.length === 0 && typeof options.path === 'string') {
- pathname = url.parse(options.path).pathname || '';
- }
- method = options.method || 'GET';
- origin = `${options.protocol || 'http:'}//${options.host}`;
- }
- catch (e) {
- return original.apply(this, arguments);
- }
- }
- const request = original.apply(this, arguments);
- if (plugin.isIgnored(origin + pathname, request, plugin.options.ignoreOutgoingUrls)) {
- return request;
- }
- plugin.tracer.wrapEmitter(request);
- plugin.logger.debug('%s plugin outgoingRequest', plugin.moduleName);
- const traceOptions = {
- name: `${kind.toLowerCase()}-${(method || 'GET').toLowerCase()}`,
- kind: core_1.SpanKind.CLIENT
- };
- if (!plugin.tracer.currentRootSpan) {
- plugin.logger.debug('outgoingRequest starting a root span');
- return plugin.tracer.startRootSpan(traceOptions, plugin.getMakeRequestTraceFunction(request, options, plugin));
- }
- else {
- plugin.logger.debug('outgoingRequest starting a child span');
- const span = plugin.tracer.startChildSpan(traceOptions.name, traceOptions.kind);
- return (plugin.getMakeRequestTraceFunction(request, options, plugin))(span);
- }
- };
- };
- }
- getMakeRequestTraceFunction(request, options, plugin) {
- return (span) => {
- plugin.logger.debug('makeRequestTrace');
- if (!span) {
- plugin.logger.debug('makeRequestTrace span is null');
- return request;
- }
- const setter = {
- setHeader(name, value) {
- if (plugin.hasExpectHeader(options) && options.headers) {
- if (options.__cloned !== true) {
- options = Object.assign({}, options);
- options.headers = Object.assign({}, options.headers);
- options.__cloned = true;
- }
- options.headers[name] = value;
- }
- else {
- request.setHeader(name, value);
- }
- }
- };
- const propagation = plugin.tracer.propagation;
- if (propagation) {
- propagation.inject(setter, span.spanContext);
- }
- request.on('response', (response) => {
- plugin.tracer.wrapEmitter(response);
- plugin.logger.debug('outgoingRequest on response()');
- response.on('end', () => {
- plugin.logger.debug('outgoingRequest on end()');
- const method = response.method ? response.method : 'GET';
- const headers = options.headers;
- const userAgent = headers ? (headers['user-agent'] || headers['User-Agent']) : null;
- if (options.host || options.hostname) {
- const value = options.host || options.hostname;
- span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_HOST, `${value}`);
- }
- span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_METHOD, method);
- 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}`);
- span.setStatus(HttpPlugin.convertTraceStatus(response.statusCode || 0));
- span.addMessageEvent(core_1.MessageEventType.SENT, uuid.v4().split('-').join(''));
- span.end();
- });
- response.on('error', error => {
- span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_NAME, error.name);
- span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_MESSAGE, error.message);
- span.setStatus(core_1.CanonicalCode.UNKNOWN);
- span.end();
- });
- });
- request.on('error', error => {
- span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_NAME, error.name);
- span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_MESSAGE, error.message);
- span.setStatus(core_1.CanonicalCode.UNKNOWN);
- span.end();
- });
- plugin.logger.debug('makeRequestTrace return request');
- return request;
- };
- }
- createSpan(options, fn) {
- const forceChildspan = this.options.createSpanWithNet === true;
- if (forceChildspan) {
- const span = this.tracer.startChildSpan(options.name, options.kind);
- return fn(span);
- }
- else {
- return this.tracer.startRootSpan(options, fn);
- }
- }
- static convertTraceStatus(statusCode) {
- if (statusCode < 200 || statusCode > 504) {
- return TraceStatusCodes.UNKNOWN;
- }
- else if (statusCode >= 200 && statusCode < 400) {
- return TraceStatusCodes.OK;
- }
- else {
- switch (statusCode) {
- case (400):
- return TraceStatusCodes.INVALID_ARGUMENT;
- case (504):
- return TraceStatusCodes.DEADLINE_EXCEEDED;
- case (404):
- return TraceStatusCodes.NOT_FOUND;
- case (403):
- return TraceStatusCodes.PERMISSION_DENIED;
- case (401):
- return TraceStatusCodes.UNAUTHENTICATED;
- case (429):
- return TraceStatusCodes.RESOURCE_EXHAUSTED;
- case (501):
- return TraceStatusCodes.UNIMPLEMENTED;
- case (503):
- return TraceStatusCodes.UNAVAILABLE;
- default:
- return TraceStatusCodes.UNKNOWN;
- }
- }
- }
- hasExpectHeader(options) {
- return !!(options.headers &&
- options.headers.Expect);
- }
- }
- HttpPlugin.ATTRIBUTE_HTTP_HOST = 'http.host';
- HttpPlugin.ATTRIBUTE_HTTP_METHOD = 'http.method';
- HttpPlugin.ATTRIBUTE_HTTP_PATH = 'http.path';
- HttpPlugin.ATTRIBUTE_HTTP_ROUTE = 'http.route';
- HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT = 'http.user_agent';
- HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE = 'http.status_code';
- HttpPlugin.ATTRIBUTE_HTTP_ERROR_NAME = 'http.error_name';
- HttpPlugin.ATTRIBUTE_HTTP_ERROR_MESSAGE = 'http.error_message';
- exports.HttpPlugin = HttpPlugin;
- var TraceStatusCodes;
- (function (TraceStatusCodes) {
- TraceStatusCodes[TraceStatusCodes["UNKNOWN"] = 2] = "UNKNOWN";
- TraceStatusCodes[TraceStatusCodes["OK"] = 0] = "OK";
- TraceStatusCodes[TraceStatusCodes["INVALID_ARGUMENT"] = 3] = "INVALID_ARGUMENT";
- TraceStatusCodes[TraceStatusCodes["DEADLINE_EXCEEDED"] = 4] = "DEADLINE_EXCEEDED";
- TraceStatusCodes[TraceStatusCodes["NOT_FOUND"] = 5] = "NOT_FOUND";
- TraceStatusCodes[TraceStatusCodes["PERMISSION_DENIED"] = 7] = "PERMISSION_DENIED";
- TraceStatusCodes[TraceStatusCodes["UNAUTHENTICATED"] = 16] = "UNAUTHENTICATED";
- TraceStatusCodes[TraceStatusCodes["RESOURCE_EXHAUSTED"] = 8] = "RESOURCE_EXHAUSTED";
- TraceStatusCodes[TraceStatusCodes["UNIMPLEMENTED"] = 12] = "UNIMPLEMENTED";
- TraceStatusCodes[TraceStatusCodes["UNAVAILABLE"] = 14] = "UNAVAILABLE";
- })(TraceStatusCodes = exports.TraceStatusCodes || (exports.TraceStatusCodes = {}));
- exports.plugin = new HttpPlugin('http');
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jZW5zdXMvcGx1Z2lucy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBZ0JBLDJDQUE4STtBQUM5SSxtQ0FBa0M7QUFDbEMsaUNBQWdDO0FBQ2hDLG1DQUFrQztBQUNsQywyQkFBMEI7QUFDMUIsNkJBQTRCO0FBQzVCLHVDQUE0QztBQXdCNUMsTUFBYSxVQUFXLFNBQVEsaUJBQVU7SUFrQnhDLFlBQWEsVUFBa0I7UUFDN0IsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ25CLENBQUM7SUFLUyxVQUFVO1FBQ2xCLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5QixFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBRTNFLE9BQU8sQ0FBQyxJQUFJLENBQ1IsSUFBSSxDQUFDLGFBQWEsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLCtCQUErQixFQUFFLENBQUMsQ0FBQTtRQUkxRSxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsRUFBRTtZQUM3QyxPQUFPLENBQUMsSUFBSSxDQUNSLElBQUksQ0FBQyxhQUFhLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRTtnQkFZOUIsT0FBTyxTQUFTLFFBQVEsQ0FBRSxPQUFPLEVBQUUsUUFBUTtvQkFDekMsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUE7b0JBQ2pELEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtvQkFDVCxPQUFPLEdBQUcsQ0FBQTtnQkFDWixDQUFDLENBQUE7WUFDSCxDQUFDLENBQUMsQ0FBQTtTQUNQO1FBRUQsSUFBSSxJQUFJLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTTtZQUMvQyxJQUFJLENBQUMs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
|