Skip to content

Commit

Permalink
Update plugin to 0.48.0 (#51)
Browse files Browse the repository at this point in the history
* update babel and typescript

* update webpack

* update transactionIdGeneration

* update OT api

* update OT collector

* update OT propagator

* update context-zone-peer-dep

* update zone.js

* update plugins

* remove prototypePatch from configuration

* update README

* remove prototypePatch in example configuration

* update transaction tracing

* update instrumentation

* use new samplers

* fix userInteractionInstrumentation
  • Loading branch information
EddeCCC authored Feb 14, 2024
1 parent 8336e96 commit 5253e4f
Show file tree
Hide file tree
Showing 13 changed files with 2,248 additions and 3,638 deletions.
56 changes: 32 additions & 24 deletions README.md

Large diffs are not rendered by default.

52 changes: 26 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "boomerang-opentelemetry-plugin",
"version": "0.25.0-9",
"version": "0.48.0-1",
"description": "This is a Boomerang plugin for collecting spans using the OpenTelemetry framework and exporting them, e.g., to an OpenTelemetry collector.",
"repository": "https://github.com/NovatecConsulting/boomerang-opentelemetry-plugin",
"license": "Apache-2.0",
Expand All @@ -13,33 +13,33 @@
"build": "Create development bundle."
},
"dependencies": {
"@opentelemetry/api": "^1.0.3",
"@opentelemetry/context-zone-peer-dep": "0.25.0",
"@opentelemetry/exporter-collector": "^0.25.0",
"@opentelemetry/instrumentation-document-load": "^0.25.0",
"@opentelemetry/instrumentation-fetch": "^0.25.0",
"@opentelemetry/instrumentation-user-interaction": "^0.25.0",
"@opentelemetry/instrumentation-xml-http-request": "^0.25.0",
"@opentelemetry/propagator-b3": "^0.25.0",
"@opentelemetry/sdk-trace-web": "^0.25.0",
"regenerator-runtime": "^0.13.9",
"zone.js": "^0.11.4"
"@opentelemetry/api": "^1.7.0",
"@opentelemetry/context-zone-peer-dep": "1.21.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.48.0",
"@opentelemetry/instrumentation-document-load": "^0.35.0",
"@opentelemetry/instrumentation-fetch": "^0.48.0",
"@opentelemetry/instrumentation-user-interaction": "^0.35.0",
"@opentelemetry/instrumentation-xml-http-request": "^0.48.0",
"@opentelemetry/propagator-b3": "^1.21.0",
"@opentelemetry/sdk-trace-web": "^1.21.0",
"regenerator-runtime": "^0.14.1",
"zone.js": "^0.13.0"
},
"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.4",
"@babel/plugin-transform-runtime": "^7.11.0",
"@babel/preset-env": "^7.11.0",
"@babel/runtime": "^7.11.2",
"@types/node": "^16.0.0",
"babel-loader": "^8.1.0",
"core-js": "3",
"prettier": "^2.0.5",
"ts-loader": "^7.0.1",
"typescript": "^3.8.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-merge": "^5.7.3"
"@babel/cli": "^7.23.9",
"@babel/core": "^7.23.9",
"@babel/plugin-transform-runtime": "^7.23.9",
"@babel/preset-env": "^7.23.9",
"@babel/runtime": "^7.23.9",
"@types/node": "^20.11.17",
"babel-loader": "^9.1.3",
"core-js": "3.35.1",
"prettier": "^3.2.5",
"ts-loader": "^9.5.1",
"typescript": "^5.3.3",
"webpack": "5.90.1",
"webpack-cli": "^5.1.4",
"webpack-merge": "^5.10.0"
},
"prettier": {
"singleQuote": true
Expand Down
58 changes: 29 additions & 29 deletions src/impl/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import api, { context, trace, Span, SpanOptions, Context } from '@opentelemetry/api';
import {
AlwaysOnSampler,
AlwaysOffSampler,
TraceIdRatioBasedSampler,
HttpTraceContextPropagator,
} from '@opentelemetry/core';
import { W3CTraceContextPropagator } from '@opentelemetry/core';
import {
WebTracerConfig,
WebTracerProvider,
AlwaysOnSampler,
AlwaysOffSampler,
TraceIdRatioBasedSampler
} from '@opentelemetry/sdk-trace-web';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { ZoneContextManager } from '@opentelemetry/context-zone-peer-dep';
import {
CollectorTraceExporter,
CollectorExporterNodeConfigBase,
} from '@opentelemetry/exporter-collector';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPExporterNodeConfigBase } from '@opentelemetry/otlp-exporter-base';
import {
ConsoleSpanExporter,
SimpleSpanProcessor,
Expand All @@ -25,7 +21,6 @@ import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import { B3InjectEncoding, B3Propagator } from '@opentelemetry/propagator-b3';
import { PluginProperties, ContextFunction, PropagationHeader } from '../types';
import { patchExporter, patchExporterClass } from './patchCollectorPrototype';
import { MultiSpanProcessor, CustomSpanProcessor } from './spanProcessing';
import {
CustomDocumentLoadInstrumentation,
Expand Down Expand Up @@ -58,28 +53,32 @@ export default class OpenTelemetryTracingImpl {
instrument_fetch: {
enabled: false,
clearTimingResources: false,
path: "",
applyCustomAttributesOnSpan: null, //(span: Span, request: Request) => { },
applyCustomAttributesOnSpan: null, //(span: Span, request: Request) => { }
ignoreUrls: [],
propagateTraceHeaderCorsUrls: []
propagateTraceHeaderCorsUrls: [],
ignoreNetworkEvents: false
},
instrument_xhr: {
enabled: false,
path: "",
applyCustomAttributesOnSpan: null, // (span: Span, xhr: XMLHttpRequest) => { },
applyCustomAttributesOnSpan: null, // (span: Span, xhr: XMLHttpRequest) => { }
propagateTraceHeaderCorsUrls: [],
ignoreUrls: [],
clearTimingResources: false
},
instrument_document_load: {
enabled: false,
path: "",
applyCustomAttributesOnSpan: {
documentLoad: null, // span => { }
documentFetch: null, // span => { }
resourceFetch: null, // (span, resource) => { }
},
recordTransaction: false,
exporterDelay: 20
},
instrument_user_interaction: {
enabled: false,
path: "",
eventNames: [],
shouldPreventSpanCreation: null // eventType => { }
},
},
global_instrumentation: {
Expand All @@ -95,9 +94,8 @@ export default class OpenTelemetryTracingImpl {
exportTimeoutMillis: 30000,
},
commonAttributes: {},
prototypeExporterPatch: false,
serviceName: undefined,
propagationHeader: PropagationHeader.TRACE_CONTEXT,
propagationHeader: PropagationHeader.TRACE_CONTEXT
};

private props: PluginProperties = {
Expand Down Expand Up @@ -149,20 +147,22 @@ export default class OpenTelemetryTracingImpl {
// use OT collector if logging to console is not enabled
if (!this.props.consoleOnly) {
// register opentelemetry collector exporter
const collectorOptions: CollectorExporterNodeConfigBase = {
const collectorOptions: OTLPExporterNodeConfigBase = {
url: this.collectorUrlFromBeaconUrl(),
headers: {}, // an optional object containing custom headers to be sent with each request
concurrencyLimit: 10, // an optional limit on pending requests
...this.props.collectorConfiguration,
};

const exporter = new CollectorTraceExporter(collectorOptions);
const exporter = new OTLPTraceExporter(collectorOptions);

// patches the collector-export in order to be compatible with Prototype
if (this.props.prototypeExporterPatch) {
patchExporter(exporter);
patchExporterClass();
}
// Patch is no longer necessary, since the new exporter does no longer use Array.from()
// TODO Remove patch after tested in production
// patches the collector-export in order to be compatible with Prototype.
// if (this.props.prototypeExporterPatch) {
// patchExporter(exporter);
// patchExporterClass();
// }

const batchSpanProcessor = new BatchSpanProcessor(exporter, {
...this.defaultProperties.exporter,
Expand Down Expand Up @@ -192,7 +192,7 @@ export default class OpenTelemetryTracingImpl {
window.addEventListener("beforeunload", (event) => {
TransactionSpanManager.getTransactionSpan().end();
this.traceProvider.forceFlush();
//Synchronous blocking is necessary, so the span can be exported successfully
// Synchronous blocking is necessary, so the span can be exported successfully
this.sleep(delay);
});
}
Expand Down Expand Up @@ -252,7 +252,7 @@ export default class OpenTelemetryTracingImpl {
});
case PropagationHeader.TRACE_CONTEXT:
default:
return new HttpTraceContextPropagator();
return new W3CTraceContextPropagator();
}
};

Expand Down
92 changes: 64 additions & 28 deletions src/impl/instrumentation/documentLoadInstrumentation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
// Also see: https://github.com/signalfx/splunk-otel-js-web/blob/main/packages/web/src/SplunkDocumentLoadInstrumentation.ts
import { InstrumentationConfig } from '@opentelemetry/instrumentation';
import { DocumentLoadInstrumentation } from '@opentelemetry/instrumentation-document-load';
/**
* Inject code into the original the OT-DocumentLoadInstrumentation as well as the OT-Tracer
* Also see: https://github.com/signalfx/splunk-otel-js-web/blob/main/packages/web/src/SplunkDocumentLoadInstrumentation.ts
*/
import {
DocumentLoadInstrumentation,
DocumentLoadInstrumentationConfig
} from '@opentelemetry/instrumentation-document-load';
import * as api from '@opentelemetry/api';
import { captureTraceParentFromPerformanceEntries } from '../transaction/servertiming';
import { PerformanceEntries } from '@opentelemetry/sdk-trace-web';
Expand All @@ -9,35 +14,46 @@ import { isTracingSuppressed } from '@opentelemetry/core/build/src/trace/suppres
import { sanitizeAttributes } from '@opentelemetry/core/build/src/common/attributes';
import { TransactionSpanManager } from '../transaction/transactionSpanManager';
import { addUrlParams } from './urlParams';
import { GlobalInstrumentationConfig, RequestParameterConfig } from '../../types';
import { GlobalInstrumentationConfig } from '../../types';
import { Context, SpanOptions } from '@opentelemetry/api';

export interface CustomDocumentLoadInstrumentationConfig extends InstrumentationConfig {
export interface CustomDocumentLoadInstrumentationConfig extends DocumentLoadInstrumentationConfig {
recordTransaction?: boolean;
exporterDelay?: number;
}

/**
* Patch the Tracer class to use the transaction span as root span
* Patch the Tracer class to use the transaction span as root span.
* For any additional instrumentation of the startSpan() function, you have to use the
* new returned function
*
* OpenTelemetry version: 0.25.0
* Original: https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-sdk-trace-base/src/Tracer.ts
* OpenTelemetry version: 0.48.0
*
* @return new startSpan() function
*/
export function patchTracerForTransactions(): (name: string, options?: SpanOptions, context?: Context) => (api.Span) {
// Overwrite startSpan() in Tracer class
// Copy of the original startSpan()-function with additional logic inside the function to determine the parentContext
/**
* Overwrite startSpan() in Tracer class
* Copy of the original startSpan()-function with additional logic inside the function to determine the parentContext
*/
const overwrittenFunction = function (
name: string,
options: api.SpanOptions = {},
context = api.context.active()
) {
// remove span from context in case a root span is requested via options
if (options.root) {
context = api.trace.deleteSpan(context);
}
const parentSpan = api.trace.getSpan(context);

if (isTracingSuppressed(context)) {
api.diag.debug('Instrumentation suppressed, returning Noop Span');
return api.trace.wrapSpanContext(api.INVALID_SPAN_CONTEXT);
const nonRecordingSpan = api.trace.wrapSpanContext(
api.INVALID_SPAN_CONTEXT
);
return nonRecordingSpan;
}

/*
Expand All @@ -46,14 +62,15 @@ export function patchTracerForTransactions(): (name: string, options?: SpanOptio
#######################################
*/

let parentContext; //getParent(options, context);
if(options.root) parentContext = undefined;
else parentContext = api.trace.getSpanContext(context);
let parentSpanContext = parentSpan?.spanContext();
// let parentSpanContext;
// if(options.root) parentSpanContext = undefined;
// else parentSpanContext = api.trace.getSpanContext(context);

if(!parentContext) {
if(!parentSpanContext) {
const transactionSpan = TransactionSpanManager.getTransactionSpan();
if(transactionSpan)
parentContext = transactionSpan.spanContext();
parentSpanContext = transactionSpan.spanContext();
}

// Use transaction span-ID for documentLoadSpan, if existing
Expand All @@ -72,41 +89,58 @@ export function patchTracerForTransactions(): (name: string, options?: SpanOptio
let traceId;
let traceState;
let parentSpanId;
if (!parentContext || !api.trace.isSpanContextValid(parentContext)) {
if (
!parentSpanContext ||
!api.trace.isSpanContextValid(parentSpanContext)
) {
// New root span.
traceId = this._idGenerator.generateTraceId();
} else {
// New child span.
traceId = parentContext.traceId;
traceState = parentContext.traceState;
parentSpanId = parentContext.spanId;
traceId = parentSpanContext.traceId;
traceState = parentSpanContext.traceState;
parentSpanId = parentSpanContext.spanId;
}

const spanKind = options.kind ?? api.SpanKind.INTERNAL;
const links = options.links ?? [];
const links = (options.links ?? []).map(link => {
return {
context: link.context,
attributes: sanitizeAttributes(link.attributes),
};
});
const attributes = sanitizeAttributes(options.attributes);
// make sampling decision
const samplingResult = this._sampler.shouldSample(
options.root
? api.trace.setSpanContext(context, api.INVALID_SPAN_CONTEXT)
: context,
context,
traceId,
name,
spanKind,
attributes,
links
);

traceState = samplingResult.traceState ?? traceState;

const traceFlags =
samplingResult.decision === api.SamplingDecision.RECORD_AND_SAMPLED
? api.TraceFlags.SAMPLED
: api.TraceFlags.NONE;
const spanContext = { traceId, spanId, traceFlags, traceState };
if (samplingResult.decision === api.SamplingDecision.NOT_RECORD) {
api.diag.debug('Recording is off, propagating context in a non-recording span');
return api.trace.wrapSpanContext(spanContext);
api.diag.debug(
'Recording is off, propagating context in a non-recording span'
);
const nonRecordingSpan = api.trace.wrapSpanContext(spanContext);
return nonRecordingSpan;
}

// Set initial span attributes. The attributes object may have been mutated
// by the sampler, so we sanitize the merged attributes before setting them.
const initAttributes = sanitizeAttributes(
Object.assign(attributes, samplingResult.attributes)
);

const span = new Span(
this,
context,
Expand All @@ -115,14 +149,16 @@ export function patchTracerForTransactions(): (name: string, options?: SpanOptio
spanKind,
parentSpanId,
links,
options.startTime
options.startTime,
undefined,
initAttributes
);
// Set default attributes
span.setAttributes(Object.assign(attributes, samplingResult.attributes));
return span;
}

// Assign the function to the Tracer
Tracer.prototype.startSpan = overwrittenFunction;
// Return the function for additional instrumentation, if necessary
return overwrittenFunction;
}

Expand Down
2 changes: 1 addition & 1 deletion src/impl/instrumentation/fetchInstrumentation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as api from '@opentelemetry/api';
import { addUrlParams } from './urlParams';
import { FetchInstrumentation, FetchInstrumentationConfig } from '@opentelemetry/instrumentation-fetch';
import { GlobalInstrumentationConfig, RequestParameterConfig } from '../../types';
import { GlobalInstrumentationConfig } from '../../types';

type ExposedFetchSuper = {
_createSpan(url: string, options: Partial<Request | RequestInit>): api.Span | undefined;
Expand Down
Loading

0 comments on commit 5253e4f

Please sign in to comment.