@opentelemetry/instrumentation-fetch
Advanced tools
Comparing version 0.57.2 to 0.200.0-dev.0
@@ -8,2 +8,5 @@ import * as api from '@opentelemetry/api'; | ||
} | ||
export interface FetchRequestHookFunction { | ||
(span: api.Span, request: Request | RequestInit): void; | ||
} | ||
/** | ||
@@ -23,2 +26,4 @@ * FetchPlugin Config | ||
applyCustomAttributesOnSpan?: FetchCustomAttributeFunction; | ||
/** Function for adding custom attributes or headers before the request is handled */ | ||
requestHook?: FetchRequestHookFunction; | ||
ignoreNetworkEvents?: boolean; | ||
@@ -96,2 +101,3 @@ /** Measure outgoing request size */ | ||
private _applyAttributesAfterFetch; | ||
private _callRequestHook; | ||
/** | ||
@@ -98,0 +104,0 @@ * Prepares a span data - needed later for matching appropriate network |
@@ -16,43 +16,2 @@ /* | ||
*/ | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
if (typeof b !== "function" && b !== null) | ||
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { | ||
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { | ||
if (ar || !(i in from)) { | ||
if (!ar) ar = Array.prototype.slice.call(from, 0, i); | ||
ar[i] = from[i]; | ||
} | ||
} | ||
return to.concat(ar || Array.prototype.slice.call(from)); | ||
}; | ||
var _a; | ||
import * as api from '@opentelemetry/api'; | ||
@@ -71,20 +30,17 @@ import { isWrapped, InstrumentationBase, safeExecuteInTheMiddle, } from '@opentelemetry/instrumentation'; | ||
// safe enough | ||
var OBSERVER_WAIT_TIME_MS = 300; | ||
var isNode = typeof process === 'object' && ((_a = process.release) === null || _a === void 0 ? void 0 : _a.name) === 'node'; | ||
const OBSERVER_WAIT_TIME_MS = 300; | ||
const isNode = typeof process === 'object' && process.release?.name === 'node'; | ||
/** | ||
* This class represents a fetch plugin for auto instrumentation | ||
*/ | ||
var FetchInstrumentation = /** @class */ (function (_super) { | ||
__extends(FetchInstrumentation, _super); | ||
function FetchInstrumentation(config) { | ||
if (config === void 0) { config = {}; } | ||
var _this = _super.call(this, '@opentelemetry/instrumentation-fetch', VERSION, config) || this; | ||
_this.component = 'fetch'; | ||
_this.version = VERSION; | ||
_this.moduleName = _this.component; | ||
_this._usedResources = new WeakSet(); | ||
_this._tasksCount = 0; | ||
return _this; | ||
export class FetchInstrumentation extends InstrumentationBase { | ||
component = 'fetch'; | ||
version = VERSION; | ||
moduleName = this.component; | ||
_usedResources = new WeakSet(); | ||
_tasksCount = 0; | ||
constructor(config = {}) { | ||
super('@opentelemetry/instrumentation-fetch', VERSION, config); | ||
} | ||
FetchInstrumentation.prototype.init = function () { }; | ||
init() { } | ||
/** | ||
@@ -95,4 +51,4 @@ * Add cors pre flight child span | ||
*/ | ||
FetchInstrumentation.prototype._addChildSpan = function (span, corsPreFlightRequest) { | ||
var childSpan = this.tracer.startSpan('CORS Preflight', { | ||
_addChildSpan(span, corsPreFlightRequest) { | ||
const childSpan = this.tracer.startSpan('CORS Preflight', { | ||
startTime: corsPreFlightRequest[web.PerformanceTimingNames.FETCH_START], | ||
@@ -102,3 +58,3 @@ }, api.trace.setSpan(api.context.active(), span)); | ||
childSpan.end(corsPreFlightRequest[web.PerformanceTimingNames.RESPONSE_END]); | ||
}; | ||
} | ||
/** | ||
@@ -109,4 +65,4 @@ * Adds more attributes to span just before ending it | ||
*/ | ||
FetchInstrumentation.prototype._addFinalSpanAttributes = function (span, response) { | ||
var parsedUrl = web.parseUrl(response.url); | ||
_addFinalSpanAttributes(span, response) { | ||
const parsedUrl = web.parseUrl(response.url); | ||
span.setAttribute(SEMATTRS_HTTP_STATUS_CODE, response.status); | ||
@@ -121,3 +77,3 @@ if (response.statusText != null) { | ||
} | ||
}; | ||
} | ||
/** | ||
@@ -128,5 +84,5 @@ * Add headers | ||
*/ | ||
FetchInstrumentation.prototype._addHeaders = function (options, spanUrl) { | ||
_addHeaders(options, spanUrl) { | ||
if (!web.shouldPropagateTraceHeaders(spanUrl, this.getConfig().propagateTraceHeaderCorsUrls)) { | ||
var headers = {}; | ||
const headers = {}; | ||
api.propagation.inject(api.context.active(), headers); | ||
@@ -140,3 +96,3 @@ if (Object.keys(headers).length > 0) { | ||
api.propagation.inject(api.context.active(), options.headers, { | ||
set: function (h, k, v) { return h.set(k, typeof v === 'string' ? v : String(v)); }, | ||
set: (h, k, v) => h.set(k, typeof v === 'string' ? v : String(v)), | ||
}); | ||
@@ -146,3 +102,3 @@ } | ||
api.propagation.inject(api.context.active(), options.headers, { | ||
set: function (h, k, v) { return h.set(k, typeof v === 'string' ? v : String(v)); }, | ||
set: (h, k, v) => h.set(k, typeof v === 'string' ? v : String(v)), | ||
}); | ||
@@ -152,11 +108,11 @@ } | ||
api.propagation.inject(api.context.active(), options.headers, { | ||
set: function (h, k, v) { return h.set(k, typeof v === 'string' ? v : String(v)); }, | ||
set: (h, k, v) => h.set(k, typeof v === 'string' ? v : String(v)), | ||
}); | ||
} | ||
else { | ||
var headers = {}; | ||
const headers = {}; | ||
api.propagation.inject(api.context.active(), headers); | ||
options.headers = Object.assign({}, headers, options.headers || {}); | ||
} | ||
}; | ||
} | ||
/** | ||
@@ -168,3 +124,3 @@ * Clears the resource timings and all resources assigned with spans | ||
*/ | ||
FetchInstrumentation.prototype._clearResources = function () { | ||
_clearResources() { | ||
if (this._tasksCount === 0 && this.getConfig().clearTimingResources) { | ||
@@ -174,3 +130,3 @@ performance.clearResourceTimings(); | ||
} | ||
}; | ||
} | ||
/** | ||
@@ -181,5 +137,3 @@ * Creates a new span | ||
*/ | ||
FetchInstrumentation.prototype._createSpan = function (url, options) { | ||
var _a; | ||
if (options === void 0) { options = {}; } | ||
_createSpan(url, options = {}) { | ||
if (core.isUrlIgnored(url, this.getConfig().ignoreUrls)) { | ||
@@ -189,13 +143,13 @@ this._diag.debug('ignoring span as url matches ignored url'); | ||
} | ||
var method = (options.method || 'GET').toUpperCase(); | ||
var spanName = "HTTP " + method; | ||
const method = (options.method || 'GET').toUpperCase(); | ||
const spanName = `HTTP ${method}`; | ||
return this.tracer.startSpan(spanName, { | ||
kind: api.SpanKind.CLIENT, | ||
attributes: (_a = {}, | ||
_a[AttributeNames.COMPONENT] = this.moduleName, | ||
_a[SEMATTRS_HTTP_METHOD] = method, | ||
_a[SEMATTRS_HTTP_URL] = url, | ||
_a), | ||
attributes: { | ||
[AttributeNames.COMPONENT]: this.moduleName, | ||
[SEMATTRS_HTTP_METHOD]: method, | ||
[SEMATTRS_HTTP_URL]: url, | ||
}, | ||
}); | ||
}; | ||
} | ||
/** | ||
@@ -207,4 +161,4 @@ * Finds appropriate resource and add network events to the span | ||
*/ | ||
FetchInstrumentation.prototype._findResourceAndAddNetworkEvents = function (span, resourcesObserver, endTime) { | ||
var resources = resourcesObserver.entries; | ||
_findResourceAndAddNetworkEvents(span, resourcesObserver, endTime) { | ||
let resources = resourcesObserver.entries; | ||
if (!resources.length) { | ||
@@ -219,7 +173,7 @@ if (!performance.getEntriesByType) { | ||
} | ||
var resource = web.getResource(resourcesObserver.spanUrl, resourcesObserver.startTime, endTime, resources, this._usedResources, 'fetch'); | ||
const resource = web.getResource(resourcesObserver.spanUrl, resourcesObserver.startTime, endTime, resources, this._usedResources, 'fetch'); | ||
if (resource.mainRequest) { | ||
var mainRequest = resource.mainRequest; | ||
const mainRequest = resource.mainRequest; | ||
this._markResourceAsUsed(mainRequest); | ||
var corsPreFlightRequest = resource.corsPreFlightRequest; | ||
const corsPreFlightRequest = resource.corsPreFlightRequest; | ||
if (corsPreFlightRequest) { | ||
@@ -231,3 +185,3 @@ this._addChildSpan(span, corsPreFlightRequest); | ||
} | ||
}; | ||
} | ||
/** | ||
@@ -239,5 +193,5 @@ * Marks certain [resource]{@link PerformanceResourceTiming} when information | ||
*/ | ||
FetchInstrumentation.prototype._markResourceAsUsed = function (resource) { | ||
_markResourceAsUsed(resource) { | ||
this._usedResources.add(resource); | ||
}; | ||
} | ||
/** | ||
@@ -249,38 +203,32 @@ * Finish span, add attributes, network events etc. | ||
*/ | ||
FetchInstrumentation.prototype._endSpan = function (span, spanData, response) { | ||
var _this = this; | ||
var endTime = core.millisToHrTime(Date.now()); | ||
var performanceEndTime = core.hrTime(); | ||
_endSpan(span, spanData, response) { | ||
const endTime = core.millisToHrTime(Date.now()); | ||
const performanceEndTime = core.hrTime(); | ||
this._addFinalSpanAttributes(span, response); | ||
setTimeout(function () { | ||
var _a; | ||
(_a = spanData.observer) === null || _a === void 0 ? void 0 : _a.disconnect(); | ||
_this._findResourceAndAddNetworkEvents(span, spanData, performanceEndTime); | ||
_this._tasksCount--; | ||
_this._clearResources(); | ||
setTimeout(() => { | ||
spanData.observer?.disconnect(); | ||
this._findResourceAndAddNetworkEvents(span, spanData, performanceEndTime); | ||
this._tasksCount--; | ||
this._clearResources(); | ||
span.end(endTime); | ||
}, OBSERVER_WAIT_TIME_MS); | ||
}; | ||
} | ||
/** | ||
* Patches the constructor of fetch | ||
*/ | ||
FetchInstrumentation.prototype._patchConstructor = function () { | ||
var _this = this; | ||
return function (original) { | ||
var plugin = _this; | ||
return function patchConstructor() { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
var self = this; | ||
var url = web.parseUrl(args[0] instanceof Request ? args[0].url : String(args[0])).href; | ||
var options = args[0] instanceof Request ? args[0] : args[1] || {}; | ||
var createdSpan = plugin._createSpan(url, options); | ||
_patchConstructor() { | ||
return original => { | ||
const plugin = this; | ||
return function patchConstructor(...args) { | ||
const self = this; | ||
const url = web.parseUrl(args[0] instanceof Request ? args[0].url : String(args[0])).href; | ||
const options = args[0] instanceof Request ? args[0] : args[1] || {}; | ||
const createdSpan = plugin._createSpan(url, options); | ||
if (!createdSpan) { | ||
return original.apply(this, args); | ||
} | ||
var spanData = plugin._prepareSpanData(url); | ||
const spanData = plugin._prepareSpanData(url); | ||
if (plugin.getConfig().measureRequestSize) { | ||
getFetchBodyLength.apply(void 0, __spreadArray([], __read(args), false)).then(function (length) { | ||
getFetchBodyLength(...args) | ||
.then(length => { | ||
if (!length) | ||
@@ -290,3 +238,3 @@ return; | ||
}) | ||
.catch(function (error) { | ||
.catch(error => { | ||
plugin._diag.warn('getFetchBodyLength', error); | ||
@@ -300,3 +248,3 @@ }); | ||
statusText: error.message, | ||
url: url, | ||
url, | ||
}); | ||
@@ -313,3 +261,3 @@ } | ||
statusText: response.statusText, | ||
url: url, | ||
url, | ||
}); | ||
@@ -320,21 +268,19 @@ } | ||
try { | ||
var resClone = response.clone(); | ||
var resClone4Hook_1 = response.clone(); | ||
var body = resClone.body; | ||
const resClone = response.clone(); | ||
const body = resClone.body; | ||
if (body) { | ||
var reader_1 = body.getReader(); | ||
var read_1 = function () { | ||
reader_1.read().then(function (_a) { | ||
var done = _a.done; | ||
const reader = body.getReader(); | ||
const read = () => { | ||
reader.read().then(({ done }) => { | ||
if (done) { | ||
endSpanOnSuccess(span, resClone4Hook_1); | ||
endSpanOnSuccess(span, response); | ||
} | ||
else { | ||
read_1(); | ||
read(); | ||
} | ||
}, function (error) { | ||
}, error => { | ||
endSpanOnError(span, error); | ||
}); | ||
}; | ||
read_1(); | ||
read(); | ||
} | ||
@@ -358,5 +304,7 @@ else { | ||
} | ||
return new Promise(function (resolve, reject) { | ||
return api.context.with(api.trace.setSpan(api.context.active(), createdSpan), function () { | ||
return new Promise((resolve, reject) => { | ||
return api.context.with(api.trace.setSpan(api.context.active(), createdSpan), () => { | ||
plugin._addHeaders(options, url); | ||
// Important to execute "_callRequestHook" after "_addHeaders", allowing the consumer code to override the request headers. | ||
plugin._callRequestHook(createdSpan, options); | ||
plugin._tasksCount++; | ||
@@ -372,15 +320,25 @@ // TypeScript complains about arrow function captured a this typed as globalThis | ||
}; | ||
}; | ||
FetchInstrumentation.prototype._applyAttributesAfterFetch = function (span, request, result) { | ||
var _this = this; | ||
var applyCustomAttributesOnSpan = this.getConfig().applyCustomAttributesOnSpan; | ||
} | ||
_applyAttributesAfterFetch(span, request, result) { | ||
const applyCustomAttributesOnSpan = this.getConfig().applyCustomAttributesOnSpan; | ||
if (applyCustomAttributesOnSpan) { | ||
safeExecuteInTheMiddle(function () { return applyCustomAttributesOnSpan(span, request, result); }, function (error) { | ||
safeExecuteInTheMiddle(() => applyCustomAttributesOnSpan(span, request, result), error => { | ||
if (!error) { | ||
return; | ||
} | ||
_this._diag.error('applyCustomAttributesOnSpan', error); | ||
this._diag.error('applyCustomAttributesOnSpan', error); | ||
}, true); | ||
} | ||
}; | ||
} | ||
_callRequestHook(span, request) { | ||
const requestHook = this.getConfig().requestHook; | ||
if (requestHook) { | ||
safeExecuteInTheMiddle(() => requestHook(span, request), error => { | ||
if (!error) { | ||
return; | ||
} | ||
this._diag.error('requestHook', error); | ||
}, true); | ||
} | ||
} | ||
/** | ||
@@ -391,11 +349,11 @@ * Prepares a span data - needed later for matching appropriate network | ||
*/ | ||
FetchInstrumentation.prototype._prepareSpanData = function (spanUrl) { | ||
var startTime = core.hrTime(); | ||
var entries = []; | ||
_prepareSpanData(spanUrl) { | ||
const startTime = core.hrTime(); | ||
const entries = []; | ||
if (typeof PerformanceObserver !== 'function') { | ||
return { entries: entries, startTime: startTime, spanUrl: spanUrl }; | ||
return { entries, startTime, spanUrl }; | ||
} | ||
var observer = new PerformanceObserver(function (list) { | ||
var perfObsEntries = list.getEntries(); | ||
perfObsEntries.forEach(function (entry) { | ||
const observer = new PerformanceObserver(list => { | ||
const perfObsEntries = list.getEntries(); | ||
perfObsEntries.forEach(entry => { | ||
if (entry.initiatorType === 'fetch' && entry.name === spanUrl) { | ||
@@ -409,8 +367,8 @@ entries.push(entry); | ||
}); | ||
return { entries: entries, observer: observer, startTime: startTime, spanUrl: spanUrl }; | ||
}; | ||
return { entries, observer, startTime, spanUrl }; | ||
} | ||
/** | ||
* implements enable function | ||
*/ | ||
FetchInstrumentation.prototype.enable = function () { | ||
enable() { | ||
if (isNode) { | ||
@@ -427,7 +385,7 @@ // Node.js v18+ *does* have a global `fetch()`, but this package does not | ||
this._wrap(_globalThis, 'fetch', this._patchConstructor()); | ||
}; | ||
} | ||
/** | ||
* implements unpatch function | ||
*/ | ||
FetchInstrumentation.prototype.disable = function () { | ||
disable() { | ||
if (isNode) { | ||
@@ -438,6 +396,4 @@ return; | ||
this._usedResources = new WeakSet(); | ||
}; | ||
return FetchInstrumentation; | ||
}(InstrumentationBase)); | ||
export { FetchInstrumentation }; | ||
} | ||
} | ||
//# sourceMappingURL=fetch.js.map |
@@ -1,2 +0,2 @@ | ||
export { FetchCustomAttributeFunction, FetchInstrumentation, FetchInstrumentationConfig, } from './fetch'; | ||
export { FetchCustomAttributeFunction, FetchRequestHookFunction, FetchInstrumentation, FetchInstrumentationConfig, } from './fetch'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -16,69 +16,6 @@ /* | ||
*/ | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
// Much of the logic here overlaps with the same utils file in opentelemetry-instrumentation-xml-http-request | ||
// These may be unified in the future. | ||
import * as api from '@opentelemetry/api'; | ||
var DIAG_LOGGER = api.diag.createComponentLogger({ | ||
const DIAG_LOGGER = api.diag.createComponentLogger({ | ||
namespace: '@opentelemetry/opentelemetry-instrumentation-fetch/utils', | ||
@@ -114,16 +51,12 @@ }); | ||
*/ | ||
export function getFetchBodyLength() { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
export function getFetchBodyLength(...args) { | ||
if (args[0] instanceof URL || typeof args[0] === 'string') { | ||
var requestInit = args[1]; | ||
if (!(requestInit === null || requestInit === void 0 ? void 0 : requestInit.body)) { | ||
const requestInit = args[1]; | ||
if (!requestInit?.body) { | ||
return Promise.resolve(); | ||
} | ||
if (requestInit.body instanceof ReadableStream) { | ||
var _a = _getBodyNonDestructively(requestInit.body), body = _a.body, length_1 = _a.length; | ||
const { body, length } = _getBodyNonDestructively(requestInit.body); | ||
requestInit.body = body; | ||
return length_1; | ||
return length; | ||
} | ||
@@ -135,4 +68,4 @@ else { | ||
else { | ||
var info = args[0]; | ||
if (!(info === null || info === void 0 ? void 0 : info.body)) { | ||
const info = args[0]; | ||
if (!info?.body) { | ||
return Promise.resolve(); | ||
@@ -143,3 +76,3 @@ } | ||
.text() | ||
.then(function (t) { return getByteLength(t); }); | ||
.then(t => getByteLength(t)); | ||
} | ||
@@ -155,29 +88,19 @@ } | ||
return { | ||
body: body, | ||
body, | ||
length: Promise.resolve(undefined), | ||
}; | ||
} | ||
var length = 0; | ||
var resolveLength; | ||
var lengthPromise = new Promise(function (resolve) { | ||
let length = 0; | ||
let resolveLength; | ||
const lengthPromise = new Promise(resolve => { | ||
resolveLength = resolve; | ||
}); | ||
var transform = new TransformStream({ | ||
start: function () { }, | ||
transform: function (chunk, controller) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var bytearray; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, chunk]; | ||
case 1: | ||
bytearray = (_a.sent()); | ||
length += bytearray.byteLength; | ||
controller.enqueue(chunk); | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
const transform = new TransformStream({ | ||
start() { }, | ||
async transform(chunk, controller) { | ||
const bytearray = (await chunk); | ||
length += bytearray.byteLength; | ||
controller.enqueue(chunk); | ||
}, | ||
flush: function () { | ||
flush() { | ||
resolveLength(length); | ||
@@ -191,2 +114,5 @@ }, | ||
} | ||
function isDocument(value) { | ||
return typeof Document !== 'undefined' && value instanceof Document; | ||
} | ||
/** | ||
@@ -198,13 +124,12 @@ * Helper function to determine payload content length for XHR requests | ||
export function getXHRBodyLength(body) { | ||
if (typeof Document !== 'undefined' && body instanceof Document) { | ||
if (isDocument(body)) { | ||
return new XMLSerializer().serializeToString(document).length; | ||
} | ||
// XMLHttpRequestBodyInit expands to the following: | ||
if (typeof body === 'string') { | ||
return getByteLength(body); | ||
} | ||
if (body instanceof Blob) { | ||
return body.size; | ||
} | ||
// ArrayBuffer | ArrayBufferView | ||
if (body.byteLength !== undefined) { | ||
return body.byteLength; | ||
} | ||
if (body instanceof FormData) { | ||
@@ -216,4 +141,5 @@ return getFormDataSize(body); | ||
} | ||
if (typeof body === 'string') { | ||
return getByteLength(body); | ||
// ArrayBuffer | ArrayBufferView | ||
if (body.byteLength !== undefined) { | ||
return body.byteLength; | ||
} | ||
@@ -223,3 +149,3 @@ DIAG_LOGGER.warn('unknown body type'); | ||
} | ||
var TEXT_ENCODER = new TextEncoder(); | ||
const TEXT_ENCODER = new TextEncoder(); | ||
function getByteLength(s) { | ||
@@ -229,22 +155,11 @@ return TEXT_ENCODER.encode(s).byteLength; | ||
function getFormDataSize(formData) { | ||
var e_1, _a; | ||
var size = 0; | ||
try { | ||
for (var _b = __values(formData.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var _d = __read(_c.value, 2), key = _d[0], value = _d[1]; | ||
size += key.length; | ||
if (value instanceof Blob) { | ||
size += value.size; | ||
} | ||
else { | ||
size += value.length; | ||
} | ||
let size = 0; | ||
for (const [key, value] of formData.entries()) { | ||
size += key.length; | ||
if (value instanceof Blob) { | ||
size += value.size; | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
else { | ||
size += value.length; | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
@@ -251,0 +166,0 @@ return size; |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "0.57.2"; | ||
export declare const VERSION = "0.200.0-dev.0"; | ||
//# sourceMappingURL=version.d.ts.map |
@@ -17,3 +17,3 @@ /* | ||
// this is autogenerated file, see scripts/version-update.js | ||
export var VERSION = '0.57.2'; | ||
export const VERSION = '0.200.0-dev.0'; | ||
//# sourceMappingURL=version.js.map |
@@ -8,2 +8,5 @@ import * as api from '@opentelemetry/api'; | ||
} | ||
export interface FetchRequestHookFunction { | ||
(span: api.Span, request: Request | RequestInit): void; | ||
} | ||
/** | ||
@@ -23,2 +26,4 @@ * FetchPlugin Config | ||
applyCustomAttributesOnSpan?: FetchCustomAttributeFunction; | ||
/** Function for adding custom attributes or headers before the request is handled */ | ||
requestHook?: FetchRequestHookFunction; | ||
ignoreNetworkEvents?: boolean; | ||
@@ -96,2 +101,3 @@ /** Measure outgoing request size */ | ||
private _applyAttributesAfterFetch; | ||
private _callRequestHook; | ||
/** | ||
@@ -98,0 +104,0 @@ * Prepares a span data - needed later for matching appropriate network |
@@ -16,3 +16,2 @@ /* | ||
*/ | ||
var _a; | ||
import * as api from '@opentelemetry/api'; | ||
@@ -32,3 +31,3 @@ import { isWrapped, InstrumentationBase, safeExecuteInTheMiddle, } from '@opentelemetry/instrumentation'; | ||
const OBSERVER_WAIT_TIME_MS = 300; | ||
const isNode = typeof process === 'object' && ((_a = process.release) === null || _a === void 0 ? void 0 : _a.name) === 'node'; | ||
const isNode = typeof process === 'object' && process.release?.name === 'node'; | ||
/** | ||
@@ -38,9 +37,9 @@ * This class represents a fetch plugin for auto instrumentation | ||
export class FetchInstrumentation extends InstrumentationBase { | ||
component = 'fetch'; | ||
version = VERSION; | ||
moduleName = this.component; | ||
_usedResources = new WeakSet(); | ||
_tasksCount = 0; | ||
constructor(config = {}) { | ||
super('@opentelemetry/instrumentation-fetch', VERSION, config); | ||
this.component = 'fetch'; | ||
this.version = VERSION; | ||
this.moduleName = this.component; | ||
this._usedResources = new WeakSet(); | ||
this._tasksCount = 0; | ||
} | ||
@@ -194,4 +193,3 @@ init() { } | ||
setTimeout(() => { | ||
var _a; | ||
(_a = spanData.observer) === null || _a === void 0 ? void 0 : _a.disconnect(); | ||
spanData.observer?.disconnect(); | ||
this._findResourceAndAddNetworkEvents(span, spanData, performanceEndTime); | ||
@@ -253,3 +251,2 @@ this._tasksCount--; | ||
const resClone = response.clone(); | ||
const resClone4Hook = response.clone(); | ||
const body = resClone.body; | ||
@@ -261,3 +258,3 @@ if (body) { | ||
if (done) { | ||
endSpanOnSuccess(span, resClone4Hook); | ||
endSpanOnSuccess(span, response); | ||
} | ||
@@ -293,2 +290,4 @@ else { | ||
plugin._addHeaders(options, url); | ||
// Important to execute "_callRequestHook" after "_addHeaders", allowing the consumer code to override the request headers. | ||
plugin._callRequestHook(createdSpan, options); | ||
plugin._tasksCount++; | ||
@@ -316,2 +315,13 @@ // TypeScript complains about arrow function captured a this typed as globalThis | ||
} | ||
_callRequestHook(span, request) { | ||
const requestHook = this.getConfig().requestHook; | ||
if (requestHook) { | ||
safeExecuteInTheMiddle(() => requestHook(span, request), error => { | ||
if (!error) { | ||
return; | ||
} | ||
this._diag.error('requestHook', error); | ||
}, true); | ||
} | ||
} | ||
/** | ||
@@ -318,0 +328,0 @@ * Prepares a span data - needed later for matching appropriate network |
@@ -1,2 +0,2 @@ | ||
export { FetchCustomAttributeFunction, FetchInstrumentation, FetchInstrumentationConfig, } from './fetch'; | ||
export { FetchCustomAttributeFunction, FetchRequestHookFunction, FetchInstrumentation, FetchInstrumentationConfig, } from './fetch'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -53,3 +53,3 @@ /* | ||
const requestInit = args[1]; | ||
if (!(requestInit === null || requestInit === void 0 ? void 0 : requestInit.body)) { | ||
if (!requestInit?.body) { | ||
return Promise.resolve(); | ||
@@ -68,3 +68,3 @@ } | ||
const info = args[0]; | ||
if (!(info === null || info === void 0 ? void 0 : info.body)) { | ||
if (!info?.body) { | ||
return Promise.resolve(); | ||
@@ -111,2 +111,5 @@ } | ||
} | ||
function isDocument(value) { | ||
return typeof Document !== 'undefined' && value instanceof Document; | ||
} | ||
/** | ||
@@ -118,13 +121,12 @@ * Helper function to determine payload content length for XHR requests | ||
export function getXHRBodyLength(body) { | ||
if (typeof Document !== 'undefined' && body instanceof Document) { | ||
if (isDocument(body)) { | ||
return new XMLSerializer().serializeToString(document).length; | ||
} | ||
// XMLHttpRequestBodyInit expands to the following: | ||
if (typeof body === 'string') { | ||
return getByteLength(body); | ||
} | ||
if (body instanceof Blob) { | ||
return body.size; | ||
} | ||
// ArrayBuffer | ArrayBufferView | ||
if (body.byteLength !== undefined) { | ||
return body.byteLength; | ||
} | ||
if (body instanceof FormData) { | ||
@@ -136,4 +138,5 @@ return getFormDataSize(body); | ||
} | ||
if (typeof body === 'string') { | ||
return getByteLength(body); | ||
// ArrayBuffer | ArrayBufferView | ||
if (body.byteLength !== undefined) { | ||
return body.byteLength; | ||
} | ||
@@ -140,0 +143,0 @@ DIAG_LOGGER.warn('unknown body type'); |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "0.57.2"; | ||
export declare const VERSION = "0.200.0-dev.0"; | ||
//# sourceMappingURL=version.d.ts.map |
@@ -17,3 +17,3 @@ /* | ||
// this is autogenerated file, see scripts/version-update.js | ||
export const VERSION = '0.57.2'; | ||
export const VERSION = '0.200.0-dev.0'; | ||
//# sourceMappingURL=version.js.map |
@@ -8,2 +8,5 @@ import * as api from '@opentelemetry/api'; | ||
} | ||
export interface FetchRequestHookFunction { | ||
(span: api.Span, request: Request | RequestInit): void; | ||
} | ||
/** | ||
@@ -23,2 +26,4 @@ * FetchPlugin Config | ||
applyCustomAttributesOnSpan?: FetchCustomAttributeFunction; | ||
/** Function for adding custom attributes or headers before the request is handled */ | ||
requestHook?: FetchRequestHookFunction; | ||
ignoreNetworkEvents?: boolean; | ||
@@ -96,2 +101,3 @@ /** Measure outgoing request size */ | ||
private _applyAttributesAfterFetch; | ||
private _callRequestHook; | ||
/** | ||
@@ -98,0 +104,0 @@ * Prepares a span data - needed later for matching appropriate network |
@@ -17,3 +17,2 @@ "use strict"; | ||
*/ | ||
var _a; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -35,3 +34,3 @@ exports.FetchInstrumentation = void 0; | ||
const OBSERVER_WAIT_TIME_MS = 300; | ||
const isNode = typeof process === 'object' && ((_a = process.release) === null || _a === void 0 ? void 0 : _a.name) === 'node'; | ||
const isNode = typeof process === 'object' && process.release?.name === 'node'; | ||
/** | ||
@@ -41,9 +40,9 @@ * This class represents a fetch plugin for auto instrumentation | ||
class FetchInstrumentation extends instrumentation_1.InstrumentationBase { | ||
component = 'fetch'; | ||
version = version_1.VERSION; | ||
moduleName = this.component; | ||
_usedResources = new WeakSet(); | ||
_tasksCount = 0; | ||
constructor(config = {}) { | ||
super('@opentelemetry/instrumentation-fetch', version_1.VERSION, config); | ||
this.component = 'fetch'; | ||
this.version = version_1.VERSION; | ||
this.moduleName = this.component; | ||
this._usedResources = new WeakSet(); | ||
this._tasksCount = 0; | ||
} | ||
@@ -197,4 +196,3 @@ init() { } | ||
setTimeout(() => { | ||
var _a; | ||
(_a = spanData.observer) === null || _a === void 0 ? void 0 : _a.disconnect(); | ||
spanData.observer?.disconnect(); | ||
this._findResourceAndAddNetworkEvents(span, spanData, performanceEndTime); | ||
@@ -256,3 +254,2 @@ this._tasksCount--; | ||
const resClone = response.clone(); | ||
const resClone4Hook = response.clone(); | ||
const body = resClone.body; | ||
@@ -264,3 +261,3 @@ if (body) { | ||
if (done) { | ||
endSpanOnSuccess(span, resClone4Hook); | ||
endSpanOnSuccess(span, response); | ||
} | ||
@@ -296,2 +293,4 @@ else { | ||
plugin._addHeaders(options, url); | ||
// Important to execute "_callRequestHook" after "_addHeaders", allowing the consumer code to override the request headers. | ||
plugin._callRequestHook(createdSpan, options); | ||
plugin._tasksCount++; | ||
@@ -319,2 +318,13 @@ // TypeScript complains about arrow function captured a this typed as globalThis | ||
} | ||
_callRequestHook(span, request) { | ||
const requestHook = this.getConfig().requestHook; | ||
if (requestHook) { | ||
(0, instrumentation_1.safeExecuteInTheMiddle)(() => requestHook(span, request), error => { | ||
if (!error) { | ||
return; | ||
} | ||
this._diag.error('requestHook', error); | ||
}, true); | ||
} | ||
} | ||
/** | ||
@@ -321,0 +331,0 @@ * Prepares a span data - needed later for matching appropriate network |
@@ -1,2 +0,2 @@ | ||
export { FetchCustomAttributeFunction, FetchInstrumentation, FetchInstrumentationConfig, } from './fetch'; | ||
export { FetchCustomAttributeFunction, FetchRequestHookFunction, FetchInstrumentation, FetchInstrumentationConfig, } from './fetch'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -56,3 +56,3 @@ "use strict"; | ||
const requestInit = args[1]; | ||
if (!(requestInit === null || requestInit === void 0 ? void 0 : requestInit.body)) { | ||
if (!requestInit?.body) { | ||
return Promise.resolve(); | ||
@@ -71,3 +71,3 @@ } | ||
const info = args[0]; | ||
if (!(info === null || info === void 0 ? void 0 : info.body)) { | ||
if (!info?.body) { | ||
return Promise.resolve(); | ||
@@ -115,2 +115,5 @@ } | ||
} | ||
function isDocument(value) { | ||
return typeof Document !== 'undefined' && value instanceof Document; | ||
} | ||
/** | ||
@@ -122,13 +125,12 @@ * Helper function to determine payload content length for XHR requests | ||
function getXHRBodyLength(body) { | ||
if (typeof Document !== 'undefined' && body instanceof Document) { | ||
if (isDocument(body)) { | ||
return new XMLSerializer().serializeToString(document).length; | ||
} | ||
// XMLHttpRequestBodyInit expands to the following: | ||
if (typeof body === 'string') { | ||
return getByteLength(body); | ||
} | ||
if (body instanceof Blob) { | ||
return body.size; | ||
} | ||
// ArrayBuffer | ArrayBufferView | ||
if (body.byteLength !== undefined) { | ||
return body.byteLength; | ||
} | ||
if (body instanceof FormData) { | ||
@@ -140,4 +142,5 @@ return getFormDataSize(body); | ||
} | ||
if (typeof body === 'string') { | ||
return getByteLength(body); | ||
// ArrayBuffer | ArrayBufferView | ||
if (body.byteLength !== undefined) { | ||
return body.byteLength; | ||
} | ||
@@ -144,0 +147,0 @@ DIAG_LOGGER.warn('unknown body type'); |
@@ -1,2 +0,2 @@ | ||
export declare const VERSION = "0.57.2"; | ||
export declare const VERSION = "0.200.0-dev.0"; | ||
//# sourceMappingURL=version.d.ts.map |
@@ -20,3 +20,3 @@ "use strict"; | ||
// this is autogenerated file, see scripts/version-update.js | ||
exports.VERSION = '0.57.2'; | ||
exports.VERSION = '0.200.0-dev.0'; | ||
//# sourceMappingURL=version.js.map |
{ | ||
"name": "@opentelemetry/instrumentation-fetch", | ||
"version": "0.57.2", | ||
"version": "0.200.0-dev.0", | ||
"description": "OpenTelemetry instrumentation for fetch http client in web browsers", | ||
@@ -37,3 +37,3 @@ "main": "build/src/index.js", | ||
"engines": { | ||
"node": ">=14" | ||
"node": "^18.19.0 || >=20.6.0" | ||
}, | ||
@@ -58,13 +58,13 @@ "files": [ | ||
"devDependencies": { | ||
"@babel/core": "7.26.0", | ||
"@babel/preset-env": "7.26.0", | ||
"@babel/core": "7.26.9", | ||
"@babel/preset-env": "7.26.9", | ||
"@opentelemetry/api": "1.9.0", | ||
"@opentelemetry/context-zone": "1.30.1", | ||
"@opentelemetry/propagator-b3": "1.30.1", | ||
"@opentelemetry/sdk-trace-base": "1.30.1", | ||
"@opentelemetry/context-zone": "2.0.0-dev.0", | ||
"@opentelemetry/propagator-b3": "2.0.0-dev.0", | ||
"@opentelemetry/sdk-trace-base": "2.0.0-dev.0", | ||
"@types/mocha": "10.0.10", | ||
"@types/node": "18.6.5", | ||
"@types/sinon": "17.0.3", | ||
"@types/sinon": "17.0.4", | ||
"@types/webpack-env": "1.16.3", | ||
"babel-loader": "8.4.1", | ||
"babel-loader": "9.2.1", | ||
"babel-plugin-istanbul": "7.0.0", | ||
@@ -79,10 +79,10 @@ "cross-var": "1.1.0", | ||
"lerna": "6.6.2", | ||
"mocha": "10.8.2", | ||
"nyc": "15.1.0", | ||
"mocha": "11.1.0", | ||
"msw": "^2.7.0", | ||
"nyc": "17.1.0", | ||
"sinon": "15.1.2", | ||
"ts-loader": "9.5.1", | ||
"typescript": "4.4.4", | ||
"ts-loader": "9.5.2", | ||
"typescript": "5.0.4", | ||
"webpack": "5.96.1", | ||
"webpack-cli": "5.1.4", | ||
"webpack-merge": "5.10.0" | ||
"webpack-cli": "6.0.1" | ||
}, | ||
@@ -93,10 +93,15 @@ "peerDependencies": { | ||
"dependencies": { | ||
"@opentelemetry/core": "1.30.1", | ||
"@opentelemetry/instrumentation": "0.57.2", | ||
"@opentelemetry/sdk-trace-web": "1.30.1", | ||
"@opentelemetry/semantic-conventions": "1.28.0" | ||
"@opentelemetry/core": "2.0.0-dev.0", | ||
"@opentelemetry/instrumentation": "0.200.0-dev.0", | ||
"@opentelemetry/sdk-trace-web": "2.0.0-dev.0", | ||
"@opentelemetry/semantic-conventions": "^1.29.0" | ||
}, | ||
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-fetch", | ||
"sideEffects": false, | ||
"gitHead": "ac8641a5dbb5df1169bd5ed25a6667a6a6f730ca" | ||
"msw": { | ||
"workerDirectory": [ | ||
"test" | ||
] | ||
}, | ||
"gitHead": "544c40984797dd2e2cccb92cce0e88b30f235b02" | ||
} |
@@ -69,7 +69,8 @@ # OpenTelemetry Fetch Instrumentation for web | ||
| Options | Type | Description | | ||
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------|-----------------------------------------------------------------------------------------| | ||
| [`applyCustomAttributesOnSpan`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L75) | `HttpCustomAttributeFunction` | Function for adding custom attributes | | ||
| [`ignoreNetworkEvents`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L77) | `boolean` | Disable network events being added as span events (network events are added by default) | | ||
| [`measureRequestSize`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L79) | `boolean` | Measure outgoing request length (outgoing request length is not measured by default) | | ||
| Options | Type | Description | | ||
| ------- | ---- | ----------- | | ||
| [`applyCustomAttributesOnSpan`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L83) | `FetchCustomAttributeFunction` | Function for adding custom attributes | | ||
| [`requestHook`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L85) | `FetchRequestHookFunction` | Function for adding custom attributes or headers before the request is handled | | ||
| [`ignoreNetworkEvents`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L87) | `boolean`| Disable network events being added as span events (network events are added by default) | | ||
| [`measureRequestSize`](https://github.com/open-telemetry/opentelemetry-js/blob/main/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L89) | `boolean` | Measure outgoing request length (outgoing request length is not measured by default) | | ||
@@ -76,0 +77,0 @@ ## Semantic Conventions |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
107
236989
2372
+ Added@opentelemetry/api-logs@0.200.0-dev.0(transitive)
+ Added@opentelemetry/core@2.0.0-dev.0(transitive)
+ Added@opentelemetry/instrumentation@0.200.0-dev.0(transitive)
+ Added@opentelemetry/resources@2.0.0-dev.0(transitive)
+ Added@opentelemetry/sdk-trace-base@2.0.0-dev.0(transitive)
+ Added@opentelemetry/sdk-trace-web@2.0.0-dev.0(transitive)
+ Added@opentelemetry/semantic-conventions@1.30.0(transitive)
- Removed@opentelemetry/api-logs@0.57.2(transitive)
- Removed@opentelemetry/core@1.30.1(transitive)
- Removed@opentelemetry/instrumentation@0.57.2(transitive)
- Removed@opentelemetry/resources@1.30.1(transitive)
- Removed@opentelemetry/sdk-trace-base@1.30.1(transitive)
- Removed@opentelemetry/sdk-trace-web@1.30.1(transitive)
- Removed@opentelemetry/semantic-conventions@1.28.0(transitive)
- Removedsemver@7.7.1(transitive)