securityos/node_modules/next/dist/server/lib/trace/tracer.js

186 lines
6.7 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
getTracer: null,
SpanStatusCode: null,
SpanKind: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
getTracer: function() {
return getTracer;
},
SpanStatusCode: function() {
return SpanStatusCode;
},
SpanKind: function() {
return SpanKind;
}
});
const _constants = require("./constants");
let api;
// we want to allow users to use their own version of @opentelemetry/api if they
// want to, so we try to require it first, and if it fails we fall back to the
// version that is bundled with Next.js
// this is because @opentelemetry/api has to be synced with the version of
// @opentelemetry/tracing that is used, and we don't want to force users to use
// the version that is bundled with Next.js.
// the API is ~stable, so this should be fine
if (process.env.NEXT_RUNTIME === "edge") {
api = require("@opentelemetry/api");
} else {
try {
api = require("@opentelemetry/api");
} catch (err) {
api = require("next/dist/compiled/@opentelemetry/api");
}
}
const { context, trace, SpanStatusCode, SpanKind } = api;
const isPromise = (p)=>{
return p !== null && typeof p === "object" && typeof p.then === "function";
};
const closeSpanWithError = (span, error)=>{
if ((error == null ? void 0 : error.bubble) === true) {
span.setAttribute("next.bubble", true);
} else {
if (error) {
span.recordException(error);
}
span.setStatus({
code: SpanStatusCode.ERROR,
message: error == null ? void 0 : error.message
});
}
span.end();
};
/** we use this map to propagate attributes from nested spans to the top span */ const rootSpanAttributesStore = new Map();
const rootSpanIdKey = api.createContextKey("next.rootSpanId");
let lastSpanId = 0;
const getSpanId = ()=>lastSpanId++;
class NextTracerImpl {
/**
* Returns an instance to the trace with configured name.
* Since wrap / trace can be defined in any place prior to actual trace subscriber initialization,
* This should be lazily evaluated.
*/ getTracerInstance() {
return trace.getTracer("next.js", "0.0.1");
}
getContext() {
return context;
}
getActiveScopeSpan() {
return trace.getSpan(context == null ? void 0 : context.active());
}
trace(...args) {
const [type, fnOrOptions, fnOrEmpty] = args;
// coerce options form overload
const { fn, options } = typeof fnOrOptions === "function" ? {
fn: fnOrOptions,
options: {}
} : {
fn: fnOrEmpty,
options: {
...fnOrOptions
}
};
if (!_constants.NextVanillaSpanAllowlist.includes(type) && process.env.NEXT_OTEL_VERBOSE !== "1" || options.hideSpan) {
return fn();
}
const spanName = options.spanName ?? type;
// Trying to get active scoped span to assign parent. If option specifies parent span manually, will try to use it.
let spanContext = this.getSpanContext((options == null ? void 0 : options.parentSpan) ?? this.getActiveScopeSpan());
let isRootSpan = false;
if (!spanContext) {
spanContext = api.ROOT_CONTEXT;
isRootSpan = true;
}
const spanId = getSpanId();
options.attributes = {
"next.span_name": spanName,
"next.span_type": type,
...options.attributes
};
return api.context.with(spanContext.setValue(rootSpanIdKey, spanId), ()=>this.getTracerInstance().startActiveSpan(spanName, options, (span)=>{
const onCleanup = ()=>{
rootSpanAttributesStore.delete(spanId);
};
if (isRootSpan) {
rootSpanAttributesStore.set(spanId, new Map(Object.entries(options.attributes ?? {})));
}
try {
if (fn.length > 1) {
return fn(span, (err)=>closeSpanWithError(span, err));
}
const result = fn(span);
if (isPromise(result)) {
result.then(()=>span.end(), (err)=>closeSpanWithError(span, err)).finally(onCleanup);
} else {
span.end();
onCleanup();
}
return result;
} catch (err) {
closeSpanWithError(span, err);
onCleanup();
throw err;
}
}));
}
wrap(...args) {
const tracer = this;
const [name, options, fn] = args.length === 3 ? args : [
args[0],
{},
args[1]
];
if (!_constants.NextVanillaSpanAllowlist.includes(name) && process.env.NEXT_OTEL_VERBOSE !== "1") {
return fn;
}
return function() {
let optionsObj = options;
if (typeof optionsObj === "function" && typeof fn === "function") {
optionsObj = optionsObj.apply(this, arguments);
}
const lastArgId = arguments.length - 1;
const cb = arguments[lastArgId];
if (typeof cb === "function") {
const scopeBoundCb = tracer.getContext().bind(context.active(), cb);
return tracer.trace(name, optionsObj, (_span, done)=>{
arguments[lastArgId] = function(err) {
done == null ? void 0 : done(err);
return scopeBoundCb.apply(this, arguments);
};
return fn.apply(this, arguments);
});
} else {
return tracer.trace(name, optionsObj, ()=>fn.apply(this, arguments));
}
};
}
startSpan(...args) {
const [type, options] = args;
const spanContext = this.getSpanContext((options == null ? void 0 : options.parentSpan) ?? this.getActiveScopeSpan());
return this.getTracerInstance().startSpan(type, options, spanContext);
}
getSpanContext(parentSpan) {
const spanContext = parentSpan ? trace.setSpan(context.active(), parentSpan) : undefined;
return spanContext;
}
getRootSpanAttributes() {
const spanId = context.active().getValue(rootSpanIdKey);
return rootSpanAttributesStore.get(spanId);
}
}
const getTracer = (()=>{
const tracer = new NextTracerImpl();
return ()=>tracer;
})();
//# sourceMappingURL=tracer.js.map