http.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const core_1 = require("@opencensus/core");
  4. const httpModule = require("http");
  5. const semver = require("semver");
  6. const shimmer = require("shimmer");
  7. const url = require("url");
  8. const uuid = require("uuid");
  9. const express_1 = require("./express");
  10. class HttpPlugin extends core_1.BasePlugin {
  11. constructor(moduleName) {
  12. super(moduleName);
  13. }
  14. applyPatch() {
  15. this.logger.debug('applying patch to %s@%s', this.moduleName, this.version);
  16. shimmer.wrap(this.moduleExports, 'request', this.getPatchOutgoingRequestFunction());
  17. if (semver.satisfies(this.version, '>=8.0.0')) {
  18. shimmer.wrap(this.moduleExports, 'get', () => {
  19. return function getTrace(options, callback) {
  20. const req = httpModule.request(options, callback);
  21. req.end();
  22. return req;
  23. };
  24. });
  25. }
  26. if (this.moduleExports && this.moduleExports.Server &&
  27. this.moduleExports.Server.prototype) {
  28. shimmer.wrap(this.moduleExports.Server.prototype, 'emit', this.getPatchIncomingRequestFunction());
  29. }
  30. else {
  31. this.logger.error('Could not apply patch to %s.emit. Interface is not as expected.', this.moduleName);
  32. }
  33. return this.moduleExports;
  34. }
  35. applyUnpatch() {
  36. shimmer.unwrap(this.moduleExports, 'request');
  37. if (semver.satisfies(this.version, '>=8.0.0')) {
  38. shimmer.unwrap(this.moduleExports, 'get');
  39. }
  40. if (this.moduleExports && this.moduleExports.Server &&
  41. this.moduleExports.Server.prototype) {
  42. shimmer.unwrap(this.moduleExports.Server.prototype, 'emit');
  43. }
  44. }
  45. isIgnored(url, request, list) {
  46. if (!list) {
  47. return false;
  48. }
  49. for (const pattern of list) {
  50. if (this.isSatisfyPattern(url, request, pattern)) {
  51. return true;
  52. }
  53. }
  54. return false;
  55. }
  56. isSatisfyPattern(url, request, pattern) {
  57. if (typeof pattern === 'string') {
  58. return pattern === url;
  59. }
  60. else if (pattern instanceof RegExp) {
  61. return pattern.test(url);
  62. }
  63. else if (typeof pattern === 'function') {
  64. return pattern(url, request);
  65. }
  66. else {
  67. throw new TypeError('Pattern is in unsupported datatype');
  68. }
  69. }
  70. getPatchIncomingRequestFunction() {
  71. return (original) => {
  72. const plugin = this;
  73. return function incomingRequest(event, ...args) {
  74. if (event !== 'request') {
  75. return original.apply(this, arguments);
  76. }
  77. const request = args[0];
  78. const response = args[1];
  79. const path = url.parse(request.url).pathname;
  80. plugin.logger.debug('%s plugin incomingRequest', plugin.moduleName);
  81. if (plugin.isIgnored(path, request, plugin.options.ignoreIncomingPaths)) {
  82. return original.apply(this, arguments);
  83. }
  84. const propagation = plugin.tracer.propagation;
  85. const headers = request.headers;
  86. const getter = {
  87. getHeader(name) {
  88. return headers[name];
  89. }
  90. };
  91. const context = propagation ? propagation.extract(getter) : null;
  92. const traceOptions = {
  93. name: path,
  94. kind: core_1.SpanKind.SERVER,
  95. spanContext: context !== null ? context : undefined
  96. };
  97. return plugin.createSpan(traceOptions, rootSpan => {
  98. if (!rootSpan)
  99. return original.apply(this, arguments);
  100. plugin.tracer.wrapEmitter(request);
  101. plugin.tracer.wrapEmitter(response);
  102. const originalEnd = response.end;
  103. response.end = function () {
  104. response.end = originalEnd;
  105. const returned = response.end.apply(this, arguments);
  106. const requestUrl = url.parse(request.url || 'localhost');
  107. const host = headers.host || 'localhost';
  108. const userAgent = (headers['user-agent'] || headers['User-Agent']);
  109. rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_HOST, host.replace(/^(.*)(\:[0-9]{1,5})/, '$1'));
  110. rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_METHOD, request.method || 'GET');
  111. rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_PATH, `${requestUrl.pathname}`);
  112. let route = `${requestUrl.path}`;
  113. const middlewareStack = request[express_1.kMiddlewareStack];
  114. if (middlewareStack) {
  115. route = middlewareStack
  116. .filter(path => path !== '/')
  117. .map(path => {
  118. return path[0] === '/' ? path : '/' + path;
  119. }).join('');
  120. }
  121. rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ROUTE, route);
  122. rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT, userAgent);
  123. rootSpan.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE, response.statusCode.toString());
  124. rootSpan.setStatus(HttpPlugin.convertTraceStatus(response.statusCode));
  125. rootSpan.addMessageEvent(core_1.MessageEventType.RECEIVED, uuid.v4().split('-').join(''));
  126. rootSpan.end();
  127. return returned;
  128. };
  129. return original.apply(this, arguments);
  130. });
  131. };
  132. };
  133. }
  134. getPatchOutgoingRequestFunction() {
  135. return (original) => {
  136. const plugin = this;
  137. const kind = plugin.moduleName === 'https' ? 'HTTPS' : 'HTTP';
  138. return function outgoingRequest(options, callback) {
  139. if (!options) {
  140. return original.apply(this, arguments);
  141. }
  142. let pathname = '';
  143. let method = 'GET';
  144. let origin = '';
  145. if (typeof (options) === 'string') {
  146. const parsedUrl = url.parse(options);
  147. options = parsedUrl;
  148. pathname = parsedUrl.pathname || '/';
  149. origin = `${parsedUrl.protocol || 'http:'}//${parsedUrl.host}`;
  150. }
  151. else {
  152. if (options.headers &&
  153. options.headers['x-opencensus-outgoing-request']) {
  154. plugin.logger.debug('header with "x-opencensus-outgoing-request" - do not trace');
  155. return original.apply(this, arguments);
  156. }
  157. try {
  158. pathname = options.pathname || '';
  159. if (pathname.length === 0 && typeof options.path === 'string') {
  160. pathname = url.parse(options.path).pathname || '';
  161. }
  162. method = options.method || 'GET';
  163. origin = `${options.protocol || 'http:'}//${options.host}`;
  164. }
  165. catch (e) {
  166. return original.apply(this, arguments);
  167. }
  168. }
  169. const request = original.apply(this, arguments);
  170. if (plugin.isIgnored(origin + pathname, request, plugin.options.ignoreOutgoingUrls)) {
  171. return request;
  172. }
  173. plugin.tracer.wrapEmitter(request);
  174. plugin.logger.debug('%s plugin outgoingRequest', plugin.moduleName);
  175. const traceOptions = {
  176. name: `${kind.toLowerCase()}-${(method || 'GET').toLowerCase()}`,
  177. kind: core_1.SpanKind.CLIENT
  178. };
  179. if (!plugin.tracer.currentRootSpan) {
  180. plugin.logger.debug('outgoingRequest starting a root span');
  181. return plugin.tracer.startRootSpan(traceOptions, plugin.getMakeRequestTraceFunction(request, options, plugin));
  182. }
  183. else {
  184. plugin.logger.debug('outgoingRequest starting a child span');
  185. const span = plugin.tracer.startChildSpan(traceOptions.name, traceOptions.kind);
  186. return (plugin.getMakeRequestTraceFunction(request, options, plugin))(span);
  187. }
  188. };
  189. };
  190. }
  191. getMakeRequestTraceFunction(request, options, plugin) {
  192. return (span) => {
  193. plugin.logger.debug('makeRequestTrace');
  194. if (!span) {
  195. plugin.logger.debug('makeRequestTrace span is null');
  196. return request;
  197. }
  198. const setter = {
  199. setHeader(name, value) {
  200. if (plugin.hasExpectHeader(options) && options.headers) {
  201. if (options.__cloned !== true) {
  202. options = Object.assign({}, options);
  203. options.headers = Object.assign({}, options.headers);
  204. options.__cloned = true;
  205. }
  206. options.headers[name] = value;
  207. }
  208. else {
  209. request.setHeader(name, value);
  210. }
  211. }
  212. };
  213. const propagation = plugin.tracer.propagation;
  214. if (propagation) {
  215. propagation.inject(setter, span.spanContext);
  216. }
  217. request.on('response', (response) => {
  218. plugin.tracer.wrapEmitter(response);
  219. plugin.logger.debug('outgoingRequest on response()');
  220. response.on('end', () => {
  221. plugin.logger.debug('outgoingRequest on end()');
  222. const method = response.method ? response.method : 'GET';
  223. const headers = options.headers;
  224. const userAgent = headers ? (headers['user-agent'] || headers['User-Agent']) : null;
  225. if (options.host || options.hostname) {
  226. const value = options.host || options.hostname;
  227. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_HOST, `${value}`);
  228. }
  229. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_METHOD, method);
  230. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_PATH, `${options.path}`);
  231. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ROUTE, `${options.path}`);
  232. if (userAgent) {
  233. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT, userAgent.toString());
  234. }
  235. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE, `${response.statusCode}`);
  236. span.setStatus(HttpPlugin.convertTraceStatus(response.statusCode || 0));
  237. span.addMessageEvent(core_1.MessageEventType.SENT, uuid.v4().split('-').join(''));
  238. span.end();
  239. });
  240. response.on('error', error => {
  241. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_NAME, error.name);
  242. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_MESSAGE, error.message);
  243. span.setStatus(core_1.CanonicalCode.UNKNOWN);
  244. span.end();
  245. });
  246. });
  247. request.on('error', error => {
  248. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_NAME, error.name);
  249. span.addAttribute(HttpPlugin.ATTRIBUTE_HTTP_ERROR_MESSAGE, error.message);
  250. span.setStatus(core_1.CanonicalCode.UNKNOWN);
  251. span.end();
  252. });
  253. plugin.logger.debug('makeRequestTrace return request');
  254. return request;
  255. };
  256. }
  257. createSpan(options, fn) {
  258. const forceChildspan = this.options.createSpanWithNet === true;
  259. if (forceChildspan) {
  260. const span = this.tracer.startChildSpan(options.name, options.kind);
  261. return fn(span);
  262. }
  263. else {
  264. return this.tracer.startRootSpan(options, fn);
  265. }
  266. }
  267. static convertTraceStatus(statusCode) {
  268. if (statusCode < 200 || statusCode > 504) {
  269. return TraceStatusCodes.UNKNOWN;
  270. }
  271. else if (statusCode >= 200 && statusCode < 400) {
  272. return TraceStatusCodes.OK;
  273. }
  274. else {
  275. switch (statusCode) {
  276. case (400):
  277. return TraceStatusCodes.INVALID_ARGUMENT;
  278. case (504):
  279. return TraceStatusCodes.DEADLINE_EXCEEDED;
  280. case (404):
  281. return TraceStatusCodes.NOT_FOUND;
  282. case (403):
  283. return TraceStatusCodes.PERMISSION_DENIED;
  284. case (401):
  285. return TraceStatusCodes.UNAUTHENTICATED;
  286. case (429):
  287. return TraceStatusCodes.RESOURCE_EXHAUSTED;
  288. case (501):
  289. return TraceStatusCodes.UNIMPLEMENTED;
  290. case (503):
  291. return TraceStatusCodes.UNAVAILABLE;
  292. default:
  293. return TraceStatusCodes.UNKNOWN;
  294. }
  295. }
  296. }
  297. hasExpectHeader(options) {
  298. return !!(options.headers &&
  299. options.headers.Expect);
  300. }
  301. }
  302. HttpPlugin.ATTRIBUTE_HTTP_HOST = 'http.host';
  303. HttpPlugin.ATTRIBUTE_HTTP_METHOD = 'http.method';
  304. HttpPlugin.ATTRIBUTE_HTTP_PATH = 'http.path';
  305. HttpPlugin.ATTRIBUTE_HTTP_ROUTE = 'http.route';
  306. HttpPlugin.ATTRIBUTE_HTTP_USER_AGENT = 'http.user_agent';
  307. HttpPlugin.ATTRIBUTE_HTTP_STATUS_CODE = 'http.status_code';
  308. HttpPlugin.ATTRIBUTE_HTTP_ERROR_NAME = 'http.error_name';
  309. HttpPlugin.ATTRIBUTE_HTTP_ERROR_MESSAGE = 'http.error_message';
  310. exports.HttpPlugin = HttpPlugin;
  311. var TraceStatusCodes;
  312. (function (TraceStatusCodes) {
  313. TraceStatusCodes[TraceStatusCodes["UNKNOWN"] = 2] = "UNKNOWN";
  314. TraceStatusCodes[TraceStatusCodes["OK"] = 0] = "OK";
  315. TraceStatusCodes[TraceStatusCodes["INVALID_ARGUMENT"] = 3] = "INVALID_ARGUMENT";
  316. TraceStatusCodes[TraceStatusCodes["DEADLINE_EXCEEDED"] = 4] = "DEADLINE_EXCEEDED";
  317. TraceStatusCodes[TraceStatusCodes["NOT_FOUND"] = 5] = "NOT_FOUND";
  318. TraceStatusCodes[TraceStatusCodes["PERMISSION_DENIED"] = 7] = "PERMISSION_DENIED";
  319. TraceStatusCodes[TraceStatusCodes["UNAUTHENTICATED"] = 16] = "UNAUTHENTICATED";
  320. TraceStatusCodes[TraceStatusCodes["RESOURCE_EXHAUSTED"] = 8] = "RESOURCE_EXHAUSTED";
  321. TraceStatusCodes[TraceStatusCodes["UNIMPLEMENTED"] = 12] = "UNIMPLEMENTED";
  322. TraceStatusCodes[TraceStatusCodes["UNAVAILABLE"] = 14] = "UNAVAILABLE";
  323. })(TraceStatusCodes = exports.TraceStatusCodes || (exports.TraceStatusCodes = {}));
  324. exports.plugin = new HttpPlugin('http');
  325. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jZW5zdXMvcGx1Z2lucy9odHRwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBZ0JBLDJDQUE4STtBQUM5SSxtQ0FBa0M7QUFDbEMsaUNBQWdDO0FBQ2hDLG1DQUFrQztBQUNsQywyQkFBMEI7QUFDMUIsNkJBQTRCO0FBQzVCLHVDQUE0QztBQXdCNUMsTUFBYSxVQUFXLFNBQVEsaUJBQVU7SUFrQnhDLFlBQWEsVUFBa0I7UUFDN0IsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFBO0lBQ25CLENBQUM7SUFLUyxVQUFVO1FBQ2xCLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLHlCQUF5QixFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBRTNFLE9BQU8sQ0FBQyxJQUFJLENBQ1IsSUFBSSxDQUFDLGFBQWEsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLCtCQUErQixFQUFFLENBQUMsQ0FBQTtRQUkxRSxJQUFJLE1BQU0sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsRUFBRTtZQUM3QyxPQUFPLENBQUMsSUFBSSxDQUNSLElBQUksQ0FBQyxhQUFhLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRTtnQkFZOUIsT0FBTyxTQUFTLFFBQVEsQ0FBRSxPQUFPLEVBQUUsUUFBUTtvQkFDekMsTUFBTSxHQUFHLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUE7b0JBQ2pELEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtvQkFDVCxPQUFPLEdBQUcsQ0FBQTtnQkFDWixDQUFDLENBQUE7WUFDSCxDQUFDLENBQUMsQ0FBQTtTQUNQO1FBRUQsSUFBSSxJQUFJLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTTtZQUMvQyxJQUFJLENBQUMs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