http2.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const core_1 = require("@opencensus/core");
  4. const http_1 = require("./http");
  5. const shimmer = require("shimmer");
  6. const url = require("url");
  7. const uuid = require("uuid");
  8. class Http2Plugin extends http_1.HttpPlugin {
  9. constructor() {
  10. super('http2');
  11. }
  12. applyPatch() {
  13. shimmer.wrap(this.moduleExports, 'createServer', this.getPatchCreateServerFunction());
  14. shimmer.wrap(this.moduleExports, 'createSecureServer', this.getPatchCreateServerFunction());
  15. shimmer.wrap(this.moduleExports, 'connect', this.getPatchConnectFunction());
  16. return this.moduleExports;
  17. }
  18. applyUnpatch() {
  19. shimmer.unwrap(this.moduleExports, 'createServer');
  20. shimmer.unwrap(this.moduleExports, 'createSecureServer');
  21. shimmer.unwrap(this.moduleExports, 'connect');
  22. }
  23. getPatchConnectFunction() {
  24. const plugin = this;
  25. return (original) => {
  26. return function patchedConnect(authority) {
  27. const client = original.apply(this, arguments);
  28. shimmer.wrap(client, 'request', (original) => (plugin.getPatchRequestFunction())(original, authority));
  29. shimmer.unwrap(plugin.moduleExports, 'connect');
  30. return client;
  31. };
  32. };
  33. }
  34. getPatchRequestFunction() {
  35. const plugin = this;
  36. return (original, authority) => {
  37. return function patchedRequest(headers) {
  38. if (headers['x-opencensus-outgoing-request']) {
  39. return original.apply(this, arguments);
  40. }
  41. const request = original.apply(this, arguments);
  42. plugin.tracer.wrapEmitter(request);
  43. const traceOptions = {
  44. name: `http2-${(headers[':method'] || 'GET').toLowerCase()}`,
  45. kind: core_1.SpanKind.CLIENT
  46. };
  47. if (!plugin.tracer.currentRootSpan) {
  48. return plugin.tracer.startRootSpan(traceOptions, plugin.getMakeHttp2RequestTraceFunction(request, headers, authority, plugin));
  49. }
  50. else {
  51. const span = plugin.tracer.startChildSpan(traceOptions.name, traceOptions.kind);
  52. return (plugin.getMakeHttp2RequestTraceFunction(request, headers, authority, plugin))(span);
  53. }
  54. };
  55. };
  56. }
  57. getMakeHttp2RequestTraceFunction(request, headers, authority, plugin) {
  58. return (span) => {
  59. if (!span)
  60. return request;
  61. const setter = {
  62. setHeader(name, value) {
  63. headers[name] = value;
  64. }
  65. };
  66. const propagation = plugin.tracer.propagation;
  67. if (propagation) {
  68. propagation.inject(setter, span.spanContext);
  69. }
  70. request.on('response', (responseHeaders) => {
  71. const status = `${responseHeaders[':status']}`;
  72. span.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_STATUS_CODE, status);
  73. span.setStatus(Http2Plugin.convertTraceStatus(parseInt(status, 10)));
  74. });
  75. request.on('end', () => {
  76. const userAgent = headers['user-agent'] || headers['User-Agent'] || null;
  77. span.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_HOST, `${url.parse(authority).host}`);
  78. span.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_METHOD, `${headers[':method']}`);
  79. span.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_PATH, `${headers[':path']}`);
  80. span.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_ROUTE, `${headers[':path']}`);
  81. if (userAgent) {
  82. span.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_USER_AGENT, `${userAgent}`);
  83. }
  84. span.addMessageEvent(core_1.MessageEventType.SENT, uuid.v4().split('-').join(''));
  85. span.end();
  86. });
  87. request.on('error', (err) => {
  88. span.addAttribute(http_1.HttpPlugin.ATTRIBUTE_HTTP_ERROR_NAME, err.name);
  89. span.addAttribute(http_1.HttpPlugin.ATTRIBUTE_HTTP_ERROR_MESSAGE, err.message);
  90. span.setStatus(core_1.CanonicalCode.UNKNOWN, err.message);
  91. span.end();
  92. });
  93. return request;
  94. };
  95. }
  96. getPatchCreateServerFunction() {
  97. const plugin = this;
  98. return (original) => {
  99. return function patchedCreateServer() {
  100. const server = original.apply(this, arguments);
  101. shimmer.wrap(server.constructor.prototype, 'emit', plugin.getPatchEmitFunction());
  102. shimmer.unwrap(plugin.moduleExports, 'createServer');
  103. shimmer.unwrap(plugin.moduleExports, 'createSecureServer');
  104. return server;
  105. };
  106. };
  107. }
  108. getPatchEmitFunction() {
  109. const plugin = this;
  110. return (original) => {
  111. return function patchedEmit(event, stream, headers) {
  112. if (event !== 'stream') {
  113. return original.apply(this, arguments);
  114. }
  115. const propagation = plugin.tracer.propagation;
  116. const getter = {
  117. getHeader(name) {
  118. return headers[name];
  119. }
  120. };
  121. const traceOptions = {
  122. name: headers[':path'],
  123. kind: core_1.SpanKind.SERVER,
  124. spanContext: propagation ? propagation.extract(getter) : null
  125. };
  126. let statusCode = 0;
  127. const originalRespond = stream.respond;
  128. stream.respond = function () {
  129. stream.respond = originalRespond;
  130. statusCode = arguments[0][':status'];
  131. return stream.respond.apply(this, arguments);
  132. };
  133. return plugin.tracer.startRootSpan(traceOptions, rootSpan => {
  134. if (!rootSpan)
  135. return original.apply(this, arguments);
  136. plugin.tracer.wrapEmitter(stream);
  137. const originalEnd = stream.end;
  138. stream.end = function () {
  139. stream.end = originalEnd;
  140. const returned = stream.end.apply(this, arguments);
  141. const userAgent = (headers['user-agent'] || headers['User-Agent'] ||
  142. null);
  143. rootSpan.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_HOST, `${headers[':authority']}`);
  144. rootSpan.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_METHOD, `${headers[':method']}`);
  145. rootSpan.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_PATH, `${headers[':path']}`);
  146. rootSpan.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_ROUTE, `${headers[':path']}`);
  147. rootSpan.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_USER_AGENT, userAgent);
  148. rootSpan.addAttribute(Http2Plugin.ATTRIBUTE_HTTP_STATUS_CODE, `${statusCode}`);
  149. rootSpan.setStatus(Http2Plugin.convertTraceStatus(statusCode));
  150. rootSpan.addMessageEvent(core_1.MessageEventType.RECEIVED, uuid.v4().split('-').join(''));
  151. rootSpan.end();
  152. return returned;
  153. };
  154. return original.apply(this, arguments);
  155. });
  156. };
  157. };
  158. }
  159. }
  160. exports.Http2Plugin = Http2Plugin;
  161. const plugin = new Http2Plugin();
  162. exports.plugin = plugin;
  163. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaHR0cDIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY2Vuc3VzL3BsdWdpbnMvaHR0cDIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFnQkEsMkNBQTBJO0FBQzFJLGlDQUFtQztBQUVuQyxtQ0FBa0M7QUFDbEMsMkJBQTBCO0FBQzFCLDZCQUE0QjtBQVU1QixNQUFhLFdBQVksU0FBUSxpQkFBVTtJQUV6QztRQUNFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUNoQixDQUFDO0lBS1MsVUFBVTtRQUNsQixPQUFPLENBQUMsSUFBSSxDQUNSLElBQUksQ0FBQyxhQUFhLEVBQUUsY0FBYyxFQUNsQyxJQUFJLENBQUMsNEJBQTRCLEVBQUUsQ0FBQyxDQUFBO1FBQ3hDLE9BQU8sQ0FBQyxJQUFJLENBQ1IsSUFBSSxDQUFDLGFBQWEsRUFBRSxvQkFBb0IsRUFDeEMsSUFBSSxDQUFDLDRCQUE0QixFQUFFLENBQUMsQ0FBQTtRQUV4QyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDLENBQUE7UUFFM0UsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFBO0lBQzNCLENBQUM7SUFHUyxZQUFZO1FBR3BCLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxjQUFjLENBQUMsQ0FBQTtRQUNsRCxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsb0JBQW9CLENBQUMsQ0FBQTtRQUN4RCxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsU0FBUyxDQUFDLENBQUE7SUFDL0MsQ0FBQztJQUVPLHVCQUF1QjtRQUM3QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUE7UUFDbkIsT0FBTyxDQUFDLFFBQXlCLEVBQWtDLEVBQUU7WUFDbkUsT0FBTyxTQUFTLGNBQWMsQ0FBcUIsU0FBaUI7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