@google-cloud/trace-agent
Advanced tools
Comparing version 3.6.1 to 4.0.0
@@ -30,3 +30,3 @@ /** | ||
export interface PhantomRootContext { | ||
readonly type: SpanType.UNCORRELATED | SpanType.UNTRACED; | ||
readonly type: SpanType.UNCORRELATED | SpanType.UNSAMPLED | SpanType.DISABLED; | ||
} | ||
@@ -88,3 +88,3 @@ /** | ||
static UNCORRELATED: RootContext; | ||
static UNTRACED: RootContext; | ||
static DISABLED: RootContext; | ||
/** | ||
@@ -91,0 +91,0 @@ * Stack traces are captured when a root span is started. Because the stack |
@@ -87,3 +87,3 @@ "use strict"; | ||
this.logger.info(`TraceCLS#constructor: Created [${config.mechanism}] CLS instance.`); | ||
this.currentCLS = new null_1.NullCLS(TraceCLS.UNTRACED); | ||
this.currentCLS = new null_1.NullCLS(TraceCLS.DISABLED); | ||
this.currentCLS.enable(); | ||
@@ -95,5 +95,3 @@ } | ||
enable() { | ||
// if this.CLSClass = NullCLS, the user specifically asked not to use | ||
// any context propagation mechanism. So nothing should change. | ||
if (!this.enabled && this.CLSClass !== null_1.NullCLS) { | ||
if (!this.enabled) { | ||
this.logger.info('TraceCLS#enable: Enabling CLS.'); | ||
@@ -110,3 +108,3 @@ this.currentCLS.disable(); | ||
this.currentCLS.disable(); | ||
this.currentCLS = new null_1.NullCLS(TraceCLS.UNTRACED); | ||
this.currentCLS = new null_1.NullCLS(TraceCLS.DISABLED); | ||
this.currentCLS.enable(); | ||
@@ -130,5 +128,5 @@ } | ||
TraceCLS.UNCORRELATED = span_data_1.UNCORRELATED_ROOT_SPAN; | ||
TraceCLS.UNTRACED = span_data_1.UNTRACED_ROOT_SPAN; | ||
TraceCLS.DISABLED = span_data_1.DISABLED_ROOT_SPAN; | ||
exports.TraceCLS = TraceCLS; | ||
exports.cls = new util_1.Singleton(TraceCLS); | ||
//# sourceMappingURL=cls.js.map |
@@ -20,3 +20,9 @@ "use strict"; | ||
// A list of well-known EventEmitter methods that add event listeners. | ||
const EVENT_EMITTER_METHODS = ['addListener', 'on', 'once', 'prependListener', 'prependOnceListener']; | ||
const EVENT_EMITTER_METHODS = [ | ||
'addListener', | ||
'on', | ||
'once', | ||
'prependListener', | ||
'prependOnceListener', | ||
]; | ||
// A symbol used to check if a method has been wrapped for context. | ||
@@ -91,3 +97,3 @@ const WRAPPED = Symbol('@google-cloud/trace-agent:AsyncHooksCLS:WRAPPED'); | ||
delete this.contexts[id]; | ||
} | ||
}, | ||
}); | ||
@@ -155,3 +161,3 @@ } | ||
writable: false, | ||
value: fn.length | ||
value: fn.length, | ||
}); | ||
@@ -162,5 +168,5 @@ return contextWrapper; | ||
const that = this; | ||
EVENT_EMITTER_METHODS.forEach((method) => { | ||
EVENT_EMITTER_METHODS.forEach(method => { | ||
if (ee[method]) { | ||
shimmer.wrap(ee, method, (oldMethod) => { | ||
shimmer.wrap(ee, method, oldMethod => { | ||
return function (event, cb) { | ||
@@ -167,0 +173,0 @@ return oldMethod.call(this, event, that.bindWithCurrentContext(cb)); |
@@ -18,2 +18,50 @@ /** | ||
export declare type ContextHeaderBehavior = 'default' | 'ignore' | 'require'; | ||
export interface RequestDetails { | ||
/** | ||
* The request timestamp. | ||
*/ | ||
timestamp: number; | ||
/** | ||
* The request URL. | ||
*/ | ||
url: string; | ||
/** | ||
* The request method. | ||
*/ | ||
method: string; | ||
/** | ||
* The parsed trace context, if it exists. | ||
*/ | ||
traceContext: { | ||
traceId: string; | ||
spanId: string; | ||
options: number; | ||
} | null; | ||
/** | ||
* The original options object used to create the root span that corresponds | ||
* to this request. | ||
*/ | ||
options: {}; | ||
} | ||
export interface TracePolicy { | ||
shouldTrace: (requestDetails: RequestDetails) => boolean; | ||
} | ||
export interface GetHeaderFunction { | ||
getHeader: (key: string) => string[] | string | undefined; | ||
} | ||
export interface SetHeaderFunction { | ||
setHeader: (key: string, value: string) => void; | ||
} | ||
export interface OpenCensusPropagation { | ||
extract: (getHeader: GetHeaderFunction) => { | ||
traceId: string; | ||
spanId: string; | ||
options?: number; | ||
} | null; | ||
inject: (setHeader: SetHeaderFunction, traceContext: { | ||
traceId: string; | ||
spanId: string; | ||
options?: number; | ||
}) => void; | ||
} | ||
/** | ||
@@ -128,21 +176,30 @@ * Available configuration options. All fields are optional. See the | ||
/** | ||
* Specifies how to use incoming trace context headers. The following options | ||
* are available: | ||
* 'default' -- Trace context will be propagated for incoming requests that | ||
* contain the context header. A new trace will be created for requests | ||
* without trace context headers. All traces are still subject to local | ||
* sampling and url filter policies. | ||
* 'require' -- Same as default, but traces won't be created for requests | ||
* without trace context headers. This should not be set for end user-facing | ||
* services, as this header is usually set by other traced services rather | ||
* than by users. | ||
* 'ignore' -- Trace context headers will always be ignored, so a new trace | ||
* with a unique ID will be created for every request. This means that a | ||
* sampling decision specified on an incoming request will be ignored. | ||
* Specifies whether to trace based on the 'traced' bit specified on incoming | ||
* trace context headers. The following options are available: | ||
* 'default' -- Don't trace incoming requests that have a trace context | ||
* header with its 'traced' bit set to 0. | ||
* 'require' -- Don't trace incoming requests that have a trace context | ||
* header with its 'traced' bit set to 0, or incoming requests without a | ||
* trace context header. | ||
* 'ignore' -- The 'traced' bit will be ignored. In other words, the context | ||
* header isn't used to determine whether a request will be traced at all. | ||
* This might be useful for aggregating traces generated by different cloud | ||
* platform projects. | ||
* All traces are still subject to local tracing policy. | ||
*/ | ||
contextHeaderBehavior?: ContextHeaderBehavior; | ||
/** | ||
* For advanced usage only. | ||
* If specified, overrides the built-in trace policy object. | ||
* Note that if any of ignoreUrls, ignoreMethods, samplingRate, or | ||
* contextHeaderBehavior is specified, an error will be thrown when start() | ||
* is called. | ||
*/ | ||
tracePolicy?: TracePolicy; | ||
/** | ||
* If specified, the Trace Agent will use this context header propagation | ||
* implementation instead of @opencensus/propagation-stackdriver, the default | ||
* trace context header format. | ||
*/ | ||
propagation?: OpenCensusPropagation; | ||
/** | ||
* Buffer the captured traces for `flushDelaySeconds` seconds before | ||
@@ -181,9 +238,2 @@ * publishing to the Stackdriver Trace API, unless the buffer fills up first. | ||
/** | ||
* Setting this to true or false is the same as setting contextHeaderBehavior | ||
* to 'ignore' or 'default' respectively. If both are explicitly set, | ||
* contextHeaderBehavior will be prioritized over this value. | ||
* Deprecated: This option will be removed in a future release. | ||
*/ | ||
ignoreContextHeader?: boolean; | ||
/** | ||
* The ID of the Google Cloud Platform project with which traces should | ||
@@ -238,18 +288,18 @@ * be associated. The value of GCLOUD_PROJECT takes precedence over this | ||
plugins: { | ||
'bluebird': string; | ||
'connect': string; | ||
'express': string; | ||
bluebird: string; | ||
connect: string; | ||
express: string; | ||
'generic-pool': string; | ||
'grpc': string; | ||
'hapi': string; | ||
'http': string; | ||
'http2': string; | ||
'koa': string; | ||
grpc: string; | ||
hapi: string; | ||
http: string; | ||
http2: string; | ||
koa: string; | ||
'mongodb-core': string; | ||
'mongoose': string; | ||
'mysql': string; | ||
'mysql2': string; | ||
'pg': string; | ||
'redis': string; | ||
'restify': string; | ||
mongoose: string; | ||
mysql: string; | ||
mysql2: string; | ||
pg: string; | ||
redis: string; | ||
restify: string; | ||
}; | ||
@@ -256,0 +306,0 @@ stackTraceLimit: number; |
@@ -37,18 +37,18 @@ "use strict"; | ||
// enable all by default | ||
'bluebird': path.join(pluginDirectory, 'plugin-bluebird.js'), | ||
'connect': path.join(pluginDirectory, 'plugin-connect.js'), | ||
'express': path.join(pluginDirectory, 'plugin-express.js'), | ||
bluebird: path.join(pluginDirectory, 'plugin-bluebird.js'), | ||
connect: path.join(pluginDirectory, 'plugin-connect.js'), | ||
express: path.join(pluginDirectory, 'plugin-express.js'), | ||
'generic-pool': path.join(pluginDirectory, 'plugin-generic-pool.js'), | ||
'grpc': path.join(pluginDirectory, 'plugin-grpc.js'), | ||
'hapi': path.join(pluginDirectory, 'plugin-hapi.js'), | ||
'http': path.join(pluginDirectory, 'plugin-http.js'), | ||
'http2': path.join(pluginDirectory, 'plugin-http2.js'), | ||
'koa': path.join(pluginDirectory, 'plugin-koa.js'), | ||
grpc: path.join(pluginDirectory, 'plugin-grpc.js'), | ||
hapi: path.join(pluginDirectory, 'plugin-hapi.js'), | ||
http: path.join(pluginDirectory, 'plugin-http.js'), | ||
http2: path.join(pluginDirectory, 'plugin-http2.js'), | ||
koa: path.join(pluginDirectory, 'plugin-koa.js'), | ||
'mongodb-core': path.join(pluginDirectory, 'plugin-mongodb-core.js'), | ||
'mongoose': path.join(pluginDirectory, 'plugin-mongoose.js'), | ||
'mysql': path.join(pluginDirectory, 'plugin-mysql.js'), | ||
'mysql2': path.join(pluginDirectory, 'plugin-mysql2.js'), | ||
'pg': path.join(pluginDirectory, 'plugin-pg.js'), | ||
'redis': path.join(pluginDirectory, 'plugin-redis.js'), | ||
'restify': path.join(pluginDirectory, 'plugin-restify.js') | ||
mongoose: path.join(pluginDirectory, 'plugin-mongoose.js'), | ||
mysql: path.join(pluginDirectory, 'plugin-mysql.js'), | ||
mysql2: path.join(pluginDirectory, 'plugin-mysql2.js'), | ||
pg: path.join(pluginDirectory, 'plugin-pg.js'), | ||
redis: path.join(pluginDirectory, 'plugin-redis.js'), | ||
restify: path.join(pluginDirectory, 'plugin-restify.js'), | ||
}, | ||
@@ -63,4 +63,4 @@ stackTraceLimit: 10, | ||
onUncaughtException: 'ignore', | ||
serviceContext: {} | ||
serviceContext: {}, | ||
}; | ||
//# sourceMappingURL=config.js.map |
@@ -48,13 +48,12 @@ /** | ||
/** | ||
* This span object was created in circumstances where a trace span could not | ||
* be created for one of the following reasons: | ||
* (1) The Trace Agent is disabled, either explicitly or because a project ID | ||
* couldn't be determined. | ||
* (2) The configured tracing policy disallows tracing for this request | ||
* (due to sampling restrictions, ignored URLs, etc.) | ||
* (3) The current incoming request contains trace context headers that | ||
* explicitly disable local tracing for the request. | ||
* This span object was created by a disabled Trace Agent, either explicitly | ||
* or because a project ID couldn't be determined. | ||
*/ | ||
DISABLED = "DISABLED", | ||
/** | ||
* This span object represents an unsampled request, and will not be | ||
* published. | ||
* Getting a span object of this type should not be considered an error. | ||
*/ | ||
UNTRACED = "UNTRACED", | ||
UNSAMPLED = "UNSAMPLED", | ||
/** | ||
@@ -61,0 +60,0 @@ * This span object was created by StackdriverTracer#runInRootSpan, and |
@@ -40,3 +40,3 @@ "use strict"; | ||
/** Maximum size of a label value in bytes. */ | ||
TRACE_SERVICE_LABEL_VALUE_LIMIT: 16 * 1024 - 1 | ||
TRACE_SERVICE_LABEL_VALUE_LIMIT: 16 * 1024 - 1, | ||
}; | ||
@@ -55,13 +55,12 @@ /** | ||
/** | ||
* This span object was created in circumstances where a trace span could not | ||
* be created for one of the following reasons: | ||
* (1) The Trace Agent is disabled, either explicitly or because a project ID | ||
* couldn't be determined. | ||
* (2) The configured tracing policy disallows tracing for this request | ||
* (due to sampling restrictions, ignored URLs, etc.) | ||
* (3) The current incoming request contains trace context headers that | ||
* explicitly disable local tracing for the request. | ||
* This span object was created by a disabled Trace Agent, either explicitly | ||
* or because a project ID couldn't be determined. | ||
*/ | ||
SpanType["DISABLED"] = "DISABLED"; | ||
/** | ||
* This span object represents an unsampled request, and will not be | ||
* published. | ||
* Getting a span object of this type should not be considered an error. | ||
*/ | ||
SpanType["UNTRACED"] = "UNTRACED"; | ||
SpanType["UNSAMPLED"] = "UNSAMPLED"; | ||
/** | ||
@@ -68,0 +67,0 @@ * This span object was created by StackdriverTracer#runInRootSpan, and |
@@ -29,2 +29,3 @@ "use strict"; | ||
const constants_1 = require("./constants"); | ||
const cls_1 = require("./cls"); | ||
let traceAgent; | ||
@@ -34,31 +35,11 @@ /** | ||
* and overriding with env variables when they are provided. | ||
* @param projectConfig The user-provided configuration object. It will not | ||
* @param userConfig The user-provided configuration object. It will not | ||
* be modified. | ||
* @return A normalized configuration object. | ||
*/ | ||
function initConfig(projectConfig) { | ||
// `|| undefined` prevents environmental variables that are empty strings | ||
// from overriding values provided in the config object passed to start(). | ||
const envConfig = { | ||
logLevel: Number(process.env.GCLOUD_TRACE_LOGLEVEL) || undefined, | ||
projectId: process.env.GCLOUD_PROJECT || undefined, | ||
serviceContext: { | ||
service: process.env.GAE_SERVICE || process.env.GAE_MODULE_NAME || undefined, | ||
version: process.env.GAE_VERSION || process.env.GAE_MODULE_VERSION || | ||
undefined, | ||
minorVersion: process.env.GAE_MINOR_VERSION || undefined | ||
} | ||
}; | ||
function initConfig(userConfig) { | ||
let envSetConfig = {}; | ||
if (!!process.env.GCLOUD_TRACE_CONFIG) { | ||
envSetConfig = | ||
require(path.resolve(process.env.GCLOUD_TRACE_CONFIG)); | ||
envSetConfig = require(path.resolve(process.env.GCLOUD_TRACE_CONFIG)); | ||
} | ||
// Internally, ignoreContextHeader is no longer being used, so convert the | ||
// user's value into a value for contextHeaderBehavior. But let this value | ||
// be overridden by the user's explicitly set value for contextHeaderBehavior. | ||
const contextHeaderBehaviorUnderride = { | ||
contextHeaderBehavior: projectConfig.ignoreContextHeader ? 'ignore' : | ||
'default' | ||
}; | ||
// Configuration order of precedence: | ||
@@ -69,25 +50,89 @@ // 1. Environment Variables | ||
// 4. Default Config (as specified in './config') | ||
const config = extend(true, { [util_1.FORCE_NEW]: projectConfig[util_1.FORCE_NEW] }, config_1.defaultConfig, envSetConfig, contextHeaderBehaviorUnderride, projectConfig, envConfig, { plugins: {} }); | ||
// The empty plugins object guarantees that plugins is a plain object, | ||
// even if it's explicitly specified in the config to be a non-object. | ||
// Enforce the upper limit for the label value size. | ||
if (config.maximumLabelValueSize > | ||
constants_1.Constants.TRACE_SERVICE_LABEL_VALUE_LIMIT) { | ||
config.maximumLabelValueSize = constants_1.Constants.TRACE_SERVICE_LABEL_VALUE_LIMIT; | ||
const mergedConfig = extend(true, {}, config_1.defaultConfig, envSetConfig, userConfig); | ||
const forceNew = userConfig[util_1.FORCE_NEW]; | ||
// Throw for improper configurations. | ||
const userSetKeys = new Set([ | ||
...Object.keys(envSetConfig), | ||
...Object.keys(userConfig), | ||
]); | ||
if (userSetKeys.has('tracePolicy')) { | ||
// If the user specified tracePolicy, they should not have also set these | ||
// other fields. | ||
const forbiddenKeys = [ | ||
'ignoreUrls', | ||
'ignoreMethods', | ||
'samplingRate', | ||
'contextHeaderBehavior', | ||
] | ||
.filter(key => userSetKeys.has(key)) | ||
.map(key => `config.${key}`); | ||
if (forbiddenKeys.length > 0) { | ||
throw new Error(`config.tracePolicy and any of [${forbiddenKeys.join(', ')}] can't be specified at the same time.`); | ||
} | ||
} | ||
// Make rootSpanNameOverride a function if not already. | ||
if (typeof config.rootSpanNameOverride === 'string') { | ||
const spanName = config.rootSpanNameOverride; | ||
config.rootSpanNameOverride = () => spanName; | ||
} | ||
else if (typeof config.rootSpanNameOverride !== 'function') { | ||
config.rootSpanNameOverride = (name) => name; | ||
} | ||
// If the CLS mechanism is set to auto-determined, decide now what it should | ||
// be. | ||
const ahAvailable = semver.satisfies(process.version, '>=8'); | ||
if (config.clsMechanism === 'auto') { | ||
config.clsMechanism = ahAvailable ? 'async-hooks' : 'async-listener'; | ||
} | ||
return config; | ||
const getInternalClsMechanism = (clsMechanism) => { | ||
// If the CLS mechanism is set to auto-determined, decide now | ||
// what it should be. | ||
const ahAvailable = semver.satisfies(process.version, '>=8'); | ||
if (clsMechanism === 'auto') { | ||
return ahAvailable | ||
? cls_1.TraceCLSMechanism.ASYNC_HOOKS | ||
: cls_1.TraceCLSMechanism.ASYNC_LISTENER; | ||
} | ||
return clsMechanism; | ||
}; | ||
const getInternalRootSpanNameOverride = (rootSpanNameOverride) => { | ||
// Make rootSpanNameOverride a function if not already. | ||
switch (typeof rootSpanNameOverride) { | ||
case 'string': | ||
return () => rootSpanNameOverride; | ||
case 'function': | ||
return rootSpanNameOverride; | ||
default: | ||
return (name) => name; | ||
} | ||
}; | ||
return { | ||
[util_1.FORCE_NEW]: forceNew, | ||
enabled: mergedConfig.enabled, | ||
logLevel: util_1.lastOf(mergedConfig.logLevel, Number(process.env.GCLOUD_TRACE_LOGLEVEL)), | ||
clsConfig: { | ||
[util_1.FORCE_NEW]: forceNew, | ||
mechanism: getInternalClsMechanism(mergedConfig.clsMechanism), | ||
}, | ||
writerConfig: { | ||
[util_1.FORCE_NEW]: forceNew, | ||
projectId: util_1.lastOf(mergedConfig.projectId, process.env.GCLOUD_PROJECT), | ||
onUncaughtException: mergedConfig.onUncaughtException, | ||
bufferSize: mergedConfig.bufferSize, | ||
flushDelaySeconds: mergedConfig.flushDelaySeconds, | ||
stackTraceLimit: mergedConfig.stackTraceLimit, | ||
maximumLabelValueSize: Math.min(mergedConfig.maximumLabelValueSize, constants_1.Constants.TRACE_SERVICE_LABEL_VALUE_LIMIT), | ||
serviceContext: { | ||
service: util_1.lastOf(mergedConfig.serviceContext.service, process.env.GAE_MODULE_NAME, process.env.GAE_SERVICE), | ||
version: util_1.lastOf(mergedConfig.serviceContext.version, process.env.GAE_MODULE_VERSION, process.env.GAE_VERSION), | ||
minorVersion: util_1.lastOf(mergedConfig.serviceContext.minorVersion, process.env.GAE_MINOR_VERSION), | ||
}, | ||
}, | ||
pluginLoaderConfig: { | ||
[util_1.FORCE_NEW]: forceNew, | ||
plugins: Object.assign({}, mergedConfig.plugins), | ||
tracerConfig: { | ||
enhancedDatabaseReporting: mergedConfig.enhancedDatabaseReporting, | ||
rootSpanNameOverride: getInternalRootSpanNameOverride(mergedConfig.rootSpanNameOverride), | ||
spansPerTraceHardLimit: mergedConfig.spansPerTraceHardLimit, | ||
spansPerTraceSoftLimit: mergedConfig.spansPerTraceSoftLimit, | ||
}, | ||
}, | ||
tracePolicyConfig: { | ||
samplingRate: mergedConfig.samplingRate, | ||
ignoreMethods: mergedConfig.ignoreMethods, | ||
ignoreUrls: mergedConfig.ignoreUrls, | ||
contextHeaderBehavior: mergedConfig.contextHeaderBehavior, | ||
}, | ||
overrides: { | ||
tracePolicy: mergedConfig.tracePolicy, | ||
propagation: mergedConfig.propagation, | ||
}, | ||
}; | ||
} | ||
@@ -112,3 +157,3 @@ /** | ||
if (normalizedConfig.enabled && | ||
normalizedConfig.clsMechanism === 'async-listener') { | ||
normalizedConfig.clsConfig.mechanism === cls_1.TraceCLSMechanism.ASYNC_LISTENER) { | ||
// This is the earliest we can load continuation-local-storage. | ||
@@ -118,3 +163,3 @@ require('continuation-local-storage'); | ||
if (!traceAgent) { | ||
traceAgent = new (require('./trace-api').StackdriverTracer)(); | ||
traceAgent = new (require('./trace-api')).StackdriverTracer(); | ||
} | ||
@@ -124,4 +169,3 @@ try { | ||
try { | ||
tracing = | ||
require('./tracing').tracing.create(normalizedConfig, traceAgent); | ||
tracing = require('./tracing').tracing.create(normalizedConfig, traceAgent); | ||
} | ||
@@ -150,3 +194,3 @@ catch (e) { | ||
if (!traceAgent) { | ||
traceAgent = new (require('./trace-api').StackdriverTracer)(); | ||
traceAgent = new (require('./trace-api')).StackdriverTracer(); | ||
} | ||
@@ -153,0 +197,0 @@ return traceAgent; |
@@ -23,3 +23,9 @@ "use strict"; | ||
*/ | ||
exports.LEVELS = ['silent', 'error', 'warn', 'info', 'debug']; | ||
exports.LEVELS = [ | ||
'silent', | ||
'error', | ||
'warn', | ||
'info', | ||
'debug', | ||
]; | ||
function logLevelToName(level) { | ||
@@ -40,5 +46,5 @@ if (typeof level === 'string') { | ||
constructor(opts) { | ||
const levelName = opts && opts.level !== undefined ? | ||
opts.level : | ||
logLevelToName(config_1.defaultConfig.logLevel); | ||
const levelName = opts && opts.level !== undefined | ||
? opts.level | ||
: logLevelToName(config_1.defaultConfig.logLevel); | ||
if (levelName === false || levelName === 'silent') { | ||
@@ -51,3 +57,3 @@ this.logger = null; | ||
prefix: `${opts && opts.tag ? opts.tag : 'unknown'} ${levelName.toUpperCase()}`, | ||
level: levelName | ||
level: levelName, | ||
}); | ||
@@ -54,0 +60,0 @@ } |
@@ -32,7 +32,6 @@ /** | ||
/** | ||
* Gets the current trace context serialized as a string, or an empty string | ||
* if it can't be generated. | ||
* @return The stringified trace context. | ||
* Gets the current trace context, or null if it can't be retrieved. | ||
* @return The trace context. | ||
*/ | ||
getTraceContext(): string; | ||
getTraceContext(): TraceContext | null; | ||
/** | ||
@@ -92,6 +91,5 @@ * Adds a key-value pair as a label to the trace span. The value will be | ||
/** | ||
* The serialized form of an object that contains information about an | ||
* existing trace context, if it exists. | ||
* An existing trace context, if it exists. | ||
*/ | ||
traceContext?: string | null; | ||
traceContext?: TraceContext | null; | ||
} | ||
@@ -168,3 +166,3 @@ export interface Tracer { | ||
/** | ||
* Generates a stringified trace context that should be set as the trace | ||
* Generates a trace context object that should be set as the trace | ||
* context header in a response to an incoming web request. This value is | ||
@@ -176,9 +174,9 @@ * based on the trace context header value in the corresponding incoming | ||
* the incoming web request, or null if the incoming request didn't have one. | ||
* @param isTraced Whether the incoming was traced. This is determined | ||
* @param isTraced Whether the incoming request was traced. This is determined | ||
* by the local tracing policy. | ||
* @returns If the response should contain the trace context within its | ||
* header, the string to be set as this header's value. Otherwise, an empty | ||
* string. | ||
* header, the context object to be serialized as this header's value. | ||
* Otherwise, null. | ||
*/ | ||
getResponseTraceContext(incomingTraceContext: string | null, isTraced: boolean): string; | ||
getResponseTraceContext(incomingTraceContext: TraceContext | null, isTraced: boolean): TraceContext | null; | ||
/** | ||
@@ -208,8 +206,16 @@ * Binds the trace context to the given function. | ||
readonly traceContextUtils: { | ||
encodeAsString: (ctx: TraceContext) => string; | ||
decodeFromString: (str: string) => TraceContext | null; | ||
encodeAsByteArray: (ctx: TraceContext) => Buffer; | ||
decodeFromByteArray: (buf: Buffer) => TraceContext | null; | ||
}; | ||
/** | ||
* A collection of functions for dealing with trace context in HTTP headers. | ||
*/ | ||
readonly propagation: Propagation; | ||
} | ||
export declare type GetHeaderFunction = (key: string) => string[] | string | null | undefined; | ||
export declare type SetHeaderFunction = (key: string, value: string) => void; | ||
export interface Propagation { | ||
extract: (getHeader: GetHeaderFunction) => TraceContext | null; | ||
inject: (setHeader: SetHeaderFunction, traceContext: TraceContext | null) => void; | ||
} | ||
export interface Monkeypatch<T> { | ||
@@ -216,0 +222,0 @@ file?: string; |
@@ -18,3 +18,4 @@ "use strict"; | ||
const shimmer = require("shimmer"); | ||
const plugin = [{ | ||
const plugin = [ | ||
{ | ||
// Bluebird is a class. | ||
@@ -31,3 +32,5 @@ // tslint:disable-next-line:variable-name | ||
return thenFn.apply(this, [ | ||
wrapIfFunction(args[0]), wrapIfFunction(args[1]), ...args.slice(2) | ||
wrapIfFunction(args[0]), | ||
wrapIfFunction(args[1]), | ||
...args.slice(2), | ||
]); | ||
@@ -37,5 +40,6 @@ }; | ||
// tslint:enable:no-any | ||
} | ||
}]; | ||
}, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-bluebird.js.map |
@@ -19,23 +19,16 @@ "use strict"; | ||
const SUPPORTED_VERSIONS = '3.x'; | ||
function getFirstHeader(req, key) { | ||
let headerValue = req.headers[key] || null; | ||
if (headerValue && typeof headerValue !== 'string') { | ||
headerValue = headerValue[0]; | ||
} | ||
return headerValue; | ||
} | ||
function createMiddleware(api) { | ||
return function middleware(req, res, next) { | ||
const options = { | ||
name: req.originalUrl ? (url_1.parse(req.originalUrl).pathname || '') : '', | ||
name: req.originalUrl ? url_1.parse(req.originalUrl).pathname || '' : '', | ||
url: req.originalUrl, | ||
method: req.method, | ||
traceContext: getFirstHeader(req, api.constants.TRACE_CONTEXT_HEADER_NAME), | ||
skipFrames: 1 | ||
traceContext: api.propagation.extract(key => req.headers[key]), | ||
skipFrames: 1, | ||
}; | ||
api.runInRootSpan(options, (root) => { | ||
api.runInRootSpan(options, root => { | ||
// Set response trace context. | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext || null, api.isRealSpan(root)); | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext, api.isRealSpan(root)); | ||
if (responseTraceContext) { | ||
res.setHeader(api.constants.TRACE_CONTEXT_HEADER_NAME, responseTraceContext); | ||
api.propagation.inject((k, v) => res.setHeader(k, v), responseTraceContext); | ||
} | ||
@@ -67,3 +60,4 @@ if (!api.isRealSpan(root)) { | ||
} | ||
const plugin = [{ | ||
const plugin = [ | ||
{ | ||
file: '', | ||
@@ -77,5 +71,6 @@ versions: SUPPORTED_VERSIONS, | ||
}; | ||
} | ||
}]; | ||
}, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-connect.js.map |
@@ -19,4 +19,3 @@ "use strict"; | ||
const shimmer = require("shimmer"); | ||
const methods = httpMethods | ||
.concat('use', 'route', 'param', 'all'); | ||
const methods = httpMethods.concat('use', 'route', 'param', 'all'); | ||
const SUPPORTED_VERSIONS = '4.x'; | ||
@@ -28,12 +27,12 @@ function patchModuleRoot(express, api) { | ||
name: req.path, | ||
traceContext: req.get(api.constants.TRACE_CONTEXT_HEADER_NAME), | ||
traceContext: api.propagation.extract(key => req.get(key)), | ||
url: req.originalUrl, | ||
method: req.method, | ||
skipFrames: 1 | ||
skipFrames: 1, | ||
}; | ||
api.runInRootSpan(options, (rootSpan) => { | ||
api.runInRootSpan(options, rootSpan => { | ||
// Set response trace context. | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext || null, api.isRealSpan(rootSpan)); | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext, api.isRealSpan(rootSpan)); | ||
if (responseTraceContext) { | ||
res.set(api.constants.TRACE_CONTEXT_HEADER_NAME, responseTraceContext); | ||
api.propagation.inject((k, v) => res.setHeader(k, v), responseTraceContext); | ||
} | ||
@@ -74,3 +73,3 @@ if (!api.isRealSpan(rootSpan)) { | ||
} | ||
methods.forEach((method) => { | ||
methods.forEach(method => { | ||
shimmer.wrap(express.application, method, applicationActionWrap); | ||
@@ -80,12 +79,14 @@ }); | ||
function unpatchModuleRoot(express) { | ||
methods.forEach((method) => { | ||
methods.forEach(method => { | ||
shimmer.unwrap(express.application, method); | ||
}); | ||
} | ||
const plugin = [{ | ||
const plugin = [ | ||
{ | ||
versions: SUPPORTED_VERSIONS, | ||
patch: patchModuleRoot, | ||
unpatch: unpatchModuleRoot | ||
}]; | ||
unpatch: unpatchModuleRoot, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-express.js.map |
@@ -43,4 +43,3 @@ "use strict"; | ||
*/ | ||
function setTraceContextFromString(metadata, stringifiedTraceContext) { | ||
const traceContext = api.traceContextUtils.decodeFromString(stringifiedTraceContext); | ||
function setTraceContextFromString(metadata, traceContext) { | ||
if (traceContext) { | ||
@@ -96,3 +95,3 @@ const metadataValue = api.traceContextUtils.encodeAsByteArray(traceContext); | ||
// gRPC. | ||
const cbIndex = args.findIndex((arg) => { | ||
const cbIndex = args.findIndex(arg => { | ||
return typeof arg === 'function'; | ||
@@ -108,5 +107,7 @@ }); | ||
// but this is an extremely rare case. | ||
let metaIndex = args.findIndex((arg) => { | ||
return !!arg && typeof arg === 'object' && arg._internal_repr && | ||
typeof arg.getMap === 'function'; | ||
let metaIndex = args.findIndex(arg => { | ||
return (!!arg && | ||
typeof arg === 'object' && | ||
arg._internal_repr && | ||
typeof arg.getMap === 'function'); | ||
}); | ||
@@ -190,4 +191,3 @@ if (metaIndex === -1) { | ||
.map(methodName => methods[methodName].originalName) | ||
.filter(originalName => !!originalName && | ||
Client.prototype.hasOwnProperty(originalName)) | ||
.filter(originalName => !!originalName && Client.prototype.hasOwnProperty(originalName)), | ||
]; | ||
@@ -209,7 +209,7 @@ shimmer.massWrap([Client.prototype], methodsToWrap, makeClientMethod); | ||
* Returns a trace context on a Metadata object if it exists and is | ||
* well-formed, or null otherwise. The result will be encoded as a string. | ||
* well-formed, or null otherwise. | ||
* @param metadata The Metadata object from which trace context should be | ||
* retrieved. | ||
*/ | ||
function getStringifiedTraceContext(metadata) { | ||
function getTraceContext(metadata) { | ||
const metadataValue = metadata.getMap()[api.constants.TRACE_CONTEXT_GRPC_METADATA_NAME]; | ||
@@ -220,8 +220,3 @@ // Entry doesn't exist. | ||
} | ||
const traceContext = api.traceContextUtils.decodeFromByteArray(metadataValue); | ||
// Value is malformed. | ||
if (!traceContext) { | ||
return null; | ||
} | ||
return api.traceContextUtils.encodeAsString(traceContext); | ||
return api.traceContextUtils.decodeFromByteArray(metadataValue); | ||
} | ||
@@ -263,6 +258,6 @@ /** | ||
url: requestName, | ||
traceContext: getStringifiedTraceContext(call.metadata), | ||
skipFrames: SKIP_FRAMES | ||
traceContext: getTraceContext(call.metadata), | ||
skipFrames: SKIP_FRAMES, | ||
}; | ||
return api.runInRootSpan(rootSpanOptions, (rootSpan) => { | ||
return api.runInRootSpan(rootSpanOptions, rootSpan => { | ||
if (!api.isRealSpan(rootSpan)) { | ||
@@ -313,6 +308,6 @@ return serverMethod.call(this, call, callback); | ||
url: requestName, | ||
traceContext: getStringifiedTraceContext(stream.metadata), | ||
skipFrames: SKIP_FRAMES | ||
traceContext: getTraceContext(stream.metadata), | ||
skipFrames: SKIP_FRAMES, | ||
}; | ||
return api.runInRootSpan(rootSpanOptions, (rootSpan) => { | ||
return api.runInRootSpan(rootSpanOptions, rootSpan => { | ||
if (!api.isRealSpan(rootSpan)) { | ||
@@ -346,3 +341,3 @@ return serverMethod.call(this, stream); | ||
}); | ||
stream.on('error', (err) => { | ||
stream.on('error', err => { | ||
if (api.enhancedDatabaseReportingEnabled()) { | ||
@@ -372,6 +367,6 @@ rootSpan.addLabel('error', err); | ||
url: requestName, | ||
traceContext: getStringifiedTraceContext(stream.metadata), | ||
skipFrames: SKIP_FRAMES | ||
traceContext: getTraceContext(stream.metadata), | ||
skipFrames: SKIP_FRAMES, | ||
}; | ||
return api.runInRootSpan(rootSpanOptions, (rootSpan) => { | ||
return api.runInRootSpan(rootSpanOptions, rootSpan => { | ||
if (!api.isRealSpan(rootSpan)) { | ||
@@ -427,6 +422,6 @@ return serverMethod.call(this, stream, callback); | ||
url: requestName, | ||
traceContext: getStringifiedTraceContext(stream.metadata), | ||
skipFrames: SKIP_FRAMES | ||
traceContext: getTraceContext(stream.metadata), | ||
skipFrames: SKIP_FRAMES, | ||
}; | ||
return api.runInRootSpan(rootSpanOptions, (rootSpan) => { | ||
return api.runInRootSpan(rootSpanOptions, rootSpan => { | ||
if (!api.isRealSpan(rootSpan)) { | ||
@@ -522,3 +517,3 @@ return serverMethod.call(this, stream); | ||
patch: patchClient, | ||
unpatch: unpatchClient | ||
unpatch: unpatchClient, | ||
}, | ||
@@ -529,3 +524,3 @@ { | ||
patch: patchMetadata, | ||
unpatch: unpatchMetadata | ||
unpatch: unpatchMetadata, | ||
}, | ||
@@ -536,3 +531,3 @@ { | ||
patch: patchServer, | ||
unpatch: unpatchServer | ||
unpatch: unpatchServer, | ||
}, | ||
@@ -543,3 +538,3 @@ { | ||
patch: patchClient, | ||
unpatch: unpatchClient | ||
unpatch: unpatchClient, | ||
}, | ||
@@ -550,3 +545,3 @@ { | ||
patch: patchMetadata, | ||
unpatch: unpatchMetadata | ||
unpatch: unpatchMetadata, | ||
}, | ||
@@ -557,6 +552,6 @@ { | ||
patch: patchServer, | ||
unpatch: unpatchServer | ||
} | ||
unpatch: unpatchServer, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-grpc.js.map |
@@ -21,9 +21,2 @@ "use strict"; | ||
const ORIGINAL = Symbol(); | ||
function getFirstHeader(req, key) { | ||
let headerValue = req.headers[key] || null; | ||
if (headerValue && typeof headerValue !== 'string') { | ||
headerValue = headerValue[0]; | ||
} | ||
return headerValue; | ||
} | ||
function instrument(api, request, continueCb) { | ||
@@ -34,13 +27,13 @@ const req = request.raw.req; | ||
const options = { | ||
name: req.url ? (url_1.parse(req.url).pathname || '') : '', | ||
name: req.url ? url_1.parse(req.url).pathname || '' : '', | ||
url: req.url, | ||
method: req.method, | ||
traceContext: getFirstHeader(req, api.constants.TRACE_CONTEXT_HEADER_NAME), | ||
skipFrames: 2 | ||
traceContext: api.propagation.extract(key => req.headers[key]), | ||
skipFrames: 2, | ||
}; | ||
return api.runInRootSpan(options, (root) => { | ||
return api.runInRootSpan(options, root => { | ||
// Set response trace context. | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext || null, api.isRealSpan(root)); | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext, api.isRealSpan(root)); | ||
if (responseTraceContext) { | ||
res.setHeader(api.constants.TRACE_CONTEXT_HEADER_NAME, responseTraceContext); | ||
api.propagation.inject((k, v) => res.setHeader(k, v), responseTraceContext); | ||
} | ||
@@ -84,3 +77,3 @@ if (!api.isRealSpan(root)) { | ||
patch: (hapi, api) => { | ||
shimmer.wrap(hapi.Server.prototype, 'connection', (connection) => { | ||
shimmer.wrap(hapi.Server.prototype, 'connection', connection => { | ||
return function connectionTrace() { | ||
@@ -95,5 +88,5 @@ const server = connection.apply(this, arguments); | ||
}, | ||
unpatch: (hapi) => { | ||
unpatch: hapi => { | ||
shimmer.unwrap(hapi.Server.prototype, 'connection'); | ||
} | ||
}, | ||
}, | ||
@@ -114,19 +107,18 @@ /** | ||
const origExecute = Request.prototype._execute; | ||
Request.prototype._execute = | ||
Object.assign(function _executeWrap() { | ||
return instrument(api, this, () => { | ||
return origExecute.apply(this, arguments); | ||
}); | ||
}, { [ORIGINAL]: origExecute }); | ||
Request.prototype._execute = Object.assign(function _executeWrap() { | ||
return instrument(api, this, () => { | ||
return origExecute.apply(this, arguments); | ||
}); | ||
}, { [ORIGINAL]: origExecute }); | ||
}, | ||
// Request is a class name. | ||
// tslint:disable-next-line:variable-name | ||
unpatch: (Request) => { | ||
unpatch: Request => { | ||
if (Request.prototype._execute[ORIGINAL]) { | ||
Request.prototype._execute = Request.prototype._execute[ORIGINAL]; | ||
} | ||
} | ||
} | ||
}, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-hapi.js.map |
@@ -22,3 +22,3 @@ "use strict"; | ||
const ERR_HTTP_HEADERS_SENT = 'ERR_HTTP_HEADERS_SENT'; | ||
const ERR_HTTP_HEADERS_SENT_MSG = 'Can\'t set headers after they are sent.'; | ||
const ERR_HTTP_HEADERS_SENT_MSG = "Can't set headers after they are sent."; | ||
// tslint:disable:no-any | ||
@@ -28,5 +28,5 @@ const isString = is.string; | ||
// This function works around that. | ||
const isURL = semver.satisfies(process.version, '>=7') ? | ||
((value) => value instanceof url.URL) : | ||
((value) => false); | ||
const isURL = semver.satisfies(process.version, '>=7') | ||
? (value) => value instanceof url.URL | ||
: (value) => false; | ||
// tslint:enable:no-any | ||
@@ -65,3 +65,3 @@ function getSpanName(options) { | ||
const host = options.hostname || options.host || 'localhost'; | ||
const portString = options.port ? (':' + options.port) : ''; | ||
const portString = options.port ? ':' + options.port : ''; | ||
// In theory we should use url.format here. However, that is | ||
@@ -75,4 +75,5 @@ // broken. See: https://github.com/joyent/node/issues/9117 and | ||
function isTraceAgentRequest(options, api) { | ||
return options && options.headers && | ||
!!options.headers[api.constants.TRACE_AGENT_REQUEST_HEADER]; | ||
return (options && | ||
options.headers && | ||
!!options.headers[api.constants.TRACE_AGENT_REQUEST_HEADER]); | ||
} | ||
@@ -124,7 +125,9 @@ function makeRequestTrace(protocol, request, api) { | ||
options.headers = Object.assign({}, options.headers); | ||
const headers = options.headers; | ||
// Inject the trace context header. | ||
options.headers[api.constants.TRACE_CONTEXT_HEADER_NAME] = | ||
span.getTraceContext(); | ||
api.propagation.inject((key, value) => { | ||
headers[key] = value; | ||
}, span.getTraceContext()); | ||
} | ||
const req = request(options, (res) => { | ||
const req = request(options, res => { | ||
api.wrapEmitter(res); | ||
@@ -141,3 +144,3 @@ let numBytes = 0; | ||
// official documentation. | ||
shimmer.wrap(res, 'on', (on) => { | ||
shimmer.wrap(res, 'on', on => { | ||
return function on_trace(eventName) { | ||
@@ -171,16 +174,18 @@ if (eventName === 'data' && !listenerAttached) { | ||
if (!traceHeaderPreinjected) { | ||
try { | ||
req.setHeader(api.constants.TRACE_CONTEXT_HEADER_NAME, span.getTraceContext()); | ||
} | ||
catch (e) { | ||
if (e.code === ERR_HTTP_HEADERS_SENT || | ||
e.message === ERR_HTTP_HEADERS_SENT_MSG) { | ||
// Swallow the error. | ||
// This would happen in the pathological case where the Expect header | ||
// exists but is not detected by hasExpectHeader. | ||
api.propagation.inject((key, value) => { | ||
try { | ||
req.setHeader(key, value); | ||
} | ||
else { | ||
throw e; | ||
catch (e) { | ||
if (e.code === ERR_HTTP_HEADERS_SENT || | ||
e.message === ERR_HTTP_HEADERS_SENT_MSG) { | ||
// Swallow the error. | ||
// This would happen in the pathological case where the Expect | ||
// header exists but is not detected by hasExpectHeader. | ||
} | ||
else { | ||
throw e; | ||
} | ||
} | ||
} | ||
}, span.getTraceContext()); | ||
} | ||
@@ -191,3 +196,3 @@ return req; | ||
function patchHttp(http, api) { | ||
shimmer.wrap(http, 'request', (request) => { | ||
shimmer.wrap(http, 'request', request => { | ||
return makeRequestTrace('http:', request, api); | ||
@@ -220,3 +225,3 @@ }); | ||
function patchHttps(https, api) { | ||
shimmer.wrap(https, 'request', (request) => { | ||
shimmer.wrap(https, 'request', request => { | ||
return makeRequestTrace('https:', request, api); | ||
@@ -253,3 +258,3 @@ }); | ||
// the public 'http' module. | ||
patch: () => require('http') | ||
patch: () => require('http'), | ||
}, | ||
@@ -261,5 +266,5 @@ { | ||
unpatch: unpatchHttps, | ||
} | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-http.js.map |
@@ -63,3 +63,5 @@ "use strict"; | ||
} | ||
const requestLifecycleSpan = api.createChildSpan({ name: getSpanName(authority) }); | ||
const requestLifecycleSpan = api.createChildSpan({ | ||
name: getSpanName(authority), | ||
}); | ||
if (!api.isRealSpan(requestLifecycleSpan)) { | ||
@@ -71,4 +73,3 @@ return request.apply(this, arguments); | ||
requestLifecycleSpan.addLabel(api.labels.HTTP_URL_LABEL_KEY, extractUrl(authority, newHeaders)); | ||
newHeaders[api.constants.TRACE_CONTEXT_HEADER_NAME] = | ||
requestLifecycleSpan.getTraceContext(); | ||
api.propagation.inject((k, v) => (newHeaders[k] = v), requestLifecycleSpan.getTraceContext()); | ||
const stream = request.call(this, newHeaders, ...Array.prototype.slice.call(arguments, 1)); | ||
@@ -79,3 +80,3 @@ api.wrapEmitter(stream); | ||
stream | ||
.on('response', (headers) => { | ||
.on('response', headers => { | ||
requestLifecycleSpan.addLabel(api.labels.HTTP_RESPONSE_CODE_LABEL_KEY, headers[':status']); | ||
@@ -102,3 +103,3 @@ }) | ||
// any of the official documentation. | ||
shimmer.wrap(stream, 'on', (on) => { | ||
shimmer.wrap(stream, 'on', on => { | ||
return function (eventName, cb) { | ||
@@ -119,6 +120,6 @@ if (eventName === 'data' && !listenerAttached) { | ||
api.wrapEmitter(session); | ||
shimmer.wrap(session, 'request', (request) => makeRequestTrace(request, authority, api)); | ||
shimmer.wrap(session, 'request', request => makeRequestTrace(request, authority, api)); | ||
} | ||
function patchHttp2(h2, api) { | ||
shimmer.wrap(h2, 'connect', (connect) => function (authority) { | ||
shimmer.wrap(h2, 'connect', connect => function (authority) { | ||
const session = connect.apply(this, arguments); | ||
@@ -125,0 +126,0 @@ patchHttp2Session(session, authority, api); |
@@ -19,9 +19,2 @@ "use strict"; | ||
const url_1 = require("url"); | ||
function getFirstHeader(req, key) { | ||
let headerValue = req.headers[key] || null; | ||
if (headerValue && typeof headerValue !== 'string') { | ||
headerValue = headerValue[0]; | ||
} | ||
return headerValue; | ||
} | ||
function startSpanForRequest(api, ctx, getNext) { | ||
@@ -32,13 +25,13 @@ const req = ctx.req; | ||
const options = { | ||
name: req.url ? (url_1.parse(req.url).pathname || '') : '', | ||
name: req.url ? url_1.parse(req.url).pathname || '' : '', | ||
url: req.url, | ||
method: req.method, | ||
traceContext: getFirstHeader(req, api.constants.TRACE_CONTEXT_HEADER_NAME), | ||
skipFrames: 2 | ||
traceContext: api.propagation.extract(key => req.headers[key]), | ||
skipFrames: 2, | ||
}; | ||
return api.runInRootSpan(options, root => { | ||
// Set response trace context. | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext || null, api.isRealSpan(root)); | ||
const responseTraceContext = api.getResponseTraceContext(options.traceContext, api.isRealSpan(root)); | ||
if (responseTraceContext) { | ||
res.setHeader(api.constants.TRACE_CONTEXT_HEADER_NAME, responseTraceContext); | ||
api.propagation.inject((k, v) => res.setHeader(k, v), responseTraceContext); | ||
} | ||
@@ -96,3 +89,3 @@ if (!api.isRealSpan(root)) { | ||
function patchUse(koa, api, createMiddlewareFunction) { | ||
shimmer.wrap(koa.prototype, 'use', (use) => { | ||
shimmer.wrap(koa.prototype, 'use', use => { | ||
return function useTrace() { | ||
@@ -114,5 +107,5 @@ if (!this._google_trace_patched) { | ||
}, | ||
unpatch: (koa) => { | ||
unpatch: koa => { | ||
shimmer.unwrap(koa.prototype, 'use'); | ||
} | ||
}, | ||
}, | ||
@@ -125,8 +118,8 @@ { | ||
}, | ||
unpatch: (koa) => { | ||
unpatch: koa => { | ||
shimmer.unwrap(koa.prototype, 'use'); | ||
} | ||
} | ||
}, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-koa.js.map |
@@ -54,8 +54,8 @@ "use strict"; | ||
this.tracer = tracer; | ||
this.maybePopulateLabelsFromInputs = | ||
tracer.enhancedDatabaseReportingEnabled() ? populateLabelsFromInputs : | ||
noOp; | ||
this.maybePopulateLabelsFromOutputs = | ||
tracer.enhancedDatabaseReportingEnabled() ? populateLabelsFromOutputs : | ||
noOp; | ||
this.maybePopulateLabelsFromInputs = tracer.enhancedDatabaseReportingEnabled() | ||
? populateLabelsFromInputs | ||
: noOp; | ||
this.maybePopulateLabelsFromOutputs = tracer.enhancedDatabaseReportingEnabled() | ||
? populateLabelsFromOutputs | ||
: noOp; | ||
} | ||
@@ -66,3 +66,3 @@ patchSubmittable(pgQuery, span) { | ||
if (pgQuery.handleError) { | ||
shimmer.wrap(pgQuery, 'handleError', (origCallback) => { | ||
shimmer.wrap(pgQuery, 'handleError', origCallback => { | ||
// Elements of args are not individually accessed. | ||
@@ -85,3 +85,3 @@ // tslint:disable:no-any | ||
if (pgQuery.handleReadyForQuery) { | ||
shimmer.wrap(pgQuery, 'handleReadyForQuery', (origCallback) => { | ||
shimmer.wrap(pgQuery, 'handleReadyForQuery', origCallback => { | ||
// Elements of args are not individually accessed. | ||
@@ -112,11 +112,11 @@ // tslint:disable:no-any | ||
patchPromise(promise, span) { | ||
return promise = promise.then((res) => { | ||
return (promise = promise.then(res => { | ||
this.maybePopulateLabelsFromOutputs(span, null, res); | ||
span.endSpan(); | ||
return res; | ||
}, (err) => { | ||
}, err => { | ||
this.maybePopulateLabelsFromOutputs(span, err); | ||
span.endSpan(); | ||
throw err; | ||
}); | ||
})); | ||
} | ||
@@ -132,3 +132,3 @@ } | ||
const pgPatch = new PostgresPatchUtility(api); | ||
shimmer.wrap(Client.prototype, 'query', (query) => { | ||
shimmer.wrap(Client.prototype, 'query', query => { | ||
// Every call to Client#query will have a Submittable object associated | ||
@@ -174,3 +174,3 @@ // with it. We need to patch two handlers (handleReadyForQuery and | ||
shimmer.unwrap(Client.prototype, 'query'); | ||
} | ||
}, | ||
}, | ||
@@ -184,3 +184,3 @@ { | ||
const pgPatch = new PostgresPatchUtility(api); | ||
shimmer.wrap(Client.prototype, 'query', (query) => { | ||
shimmer.wrap(Client.prototype, 'query', query => { | ||
return function query_trace() { | ||
@@ -240,6 +240,6 @@ const span = api.createChildSpan({ name: 'pg-query' }); | ||
shimmer.unwrap(Client.prototype, 'query'); | ||
} | ||
} | ||
}, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-pg.js.map |
@@ -38,4 +38,4 @@ "use strict"; | ||
method: req.method, | ||
traceContext: req.header(api.constants.TRACE_CONTEXT_HEADER_NAME), | ||
skipFrames: 1 | ||
traceContext: api.propagation.extract(key => req.header(key)), | ||
skipFrames: 1, | ||
}; | ||
@@ -46,3 +46,3 @@ api.runInRootSpan(options, rootSpan => { | ||
if (responseTraceContext) { | ||
res.header(api.constants.TRACE_CONTEXT_HEADER_NAME, responseTraceContext); | ||
api.propagation.inject((k, v) => res.setHeader(k, v), responseTraceContext); | ||
} | ||
@@ -73,8 +73,10 @@ if (!api.isRealSpan(rootSpan)) { | ||
} | ||
const plugin = [{ | ||
const plugin = [ | ||
{ | ||
versions: SUPPORTED_VERSIONS, | ||
patch: patchRestify, | ||
unpatch: unpatchRestify | ||
}]; | ||
unpatch: unpatchRestify, | ||
}, | ||
]; | ||
module.exports = plugin; | ||
//# sourceMappingURL=plugin-restify.js.map |
@@ -17,4 +17,5 @@ /** | ||
import { SpanType } from './constants'; | ||
import { RootSpan, Span, SpanOptions } from './plugin-types'; | ||
import { RootSpan, Span, SpanOptions, TraceContext } from './plugin-types'; | ||
import { Trace, TraceSpan } from './trace'; | ||
import * as traceUtil from './util'; | ||
/** | ||
@@ -37,3 +38,7 @@ * Represents a real trace span. | ||
constructor(trace: Trace, spanName: string, parentSpanId: string, skipFrames: number); | ||
getTraceContext(): string; | ||
getTraceContext(): { | ||
traceId: string; | ||
spanId: string; | ||
options: number; | ||
}; | ||
addLabel(key: string, value: any): void; | ||
@@ -62,2 +67,22 @@ endSpan(timestamp?: Date): void; | ||
/** | ||
* Helper (and base) class for UntracedRootSpanData. Represents an untraced | ||
* child span. | ||
*/ | ||
declare class UntracedSpanData implements Span { | ||
readonly type = SpanType.UNSAMPLED; | ||
protected readonly traceContext: TraceContext; | ||
constructor(traceId: string); | ||
getTraceContext(): traceUtil.TraceContext | null; | ||
addLabel(): void; | ||
endSpan(): void; | ||
} | ||
/** | ||
* Represents an "untraced" root span (aka not published). | ||
* For distributed trace context propagation purposes. | ||
*/ | ||
export declare class UntracedRootSpanData extends UntracedSpanData implements RootSpan { | ||
private child; | ||
createChildSpan(): Span; | ||
} | ||
/** | ||
* A virtual trace span that indicates that a real child span couldn't be | ||
@@ -71,7 +96,6 @@ * created because the correct root span couldn't be determined. | ||
* A virtual trace span that indicates that a real child span couldn't be | ||
* created because the corresponding root span was disallowed by user | ||
* configuration. | ||
* created because the Trace Agent was disabled. | ||
*/ | ||
export declare const UNTRACED_CHILD_SPAN: Span & { | ||
readonly type: SpanType.UNTRACED; | ||
export declare const DISABLED_CHILD_SPAN: Span & { | ||
readonly type: SpanType.DISABLED; | ||
}; | ||
@@ -93,8 +117,9 @@ /** | ||
*/ | ||
export declare const UNTRACED_ROOT_SPAN: Readonly<{ | ||
export declare const DISABLED_ROOT_SPAN: Readonly<{ | ||
createChildSpan(): Span & { | ||
readonly type: SpanType.UNTRACED; | ||
readonly type: SpanType.DISABLED; | ||
}; | ||
} & Span & { | ||
readonly type: SpanType.UNTRACED; | ||
readonly type: SpanType.DISABLED; | ||
}>; | ||
export {}; |
@@ -32,5 +32,5 @@ "use strict"; | ||
const randomBytes = crypto.randomBytes; | ||
const spanRandomBuffer = randomFillSync ? | ||
() => randomFillSync(spanIdBuffer) : | ||
() => randomBytes(SPAN_ID_RANDOM_BYTES); | ||
const spanRandomBuffer = randomFillSync | ||
? () => randomFillSync(spanIdBuffer) | ||
: () => randomBytes(SPAN_ID_RANDOM_BYTES); | ||
function randomSpanId() { | ||
@@ -57,3 +57,3 @@ // tslint:disable-next-line:ban Needed to parse hexadecimal. | ||
name: traceUtil.truncate(spanName, constants_1.Constants.TRACE_SERVICE_SPAN_NAME_LIMIT), | ||
startTime: (new Date()).toISOString(), | ||
startTime: new Date().toISOString(), | ||
endTime: '', | ||
@@ -63,3 +63,3 @@ spanId: randomSpanId(), | ||
parentSpanId, | ||
labels: {} | ||
labels: {}, | ||
}; | ||
@@ -71,12 +71,11 @@ this.trace.spans.push(this.span); | ||
// stack trace label has its own size constraints. | ||
this.span.labels[trace_labels_1.TraceLabels.STACK_TRACE_DETAILS_KEY] = | ||
traceUtil.truncate(JSON.stringify({ stack_frame: stackFrames }), constants_1.Constants.TRACE_SERVICE_LABEL_VALUE_LIMIT); | ||
this.span.labels[trace_labels_1.TraceLabels.STACK_TRACE_DETAILS_KEY] = traceUtil.truncate(JSON.stringify({ stack_frame: stackFrames }), constants_1.Constants.TRACE_SERVICE_LABEL_VALUE_LIMIT); | ||
} | ||
} | ||
getTraceContext() { | ||
return traceUtil.generateTraceContext({ | ||
return { | ||
traceId: this.trace.traceId.toString(), | ||
spanId: this.span.spanId.toString(), | ||
options: 1 // always traced | ||
}); | ||
options: 1, | ||
}; | ||
} | ||
@@ -114,3 +113,3 @@ // tslint:disable-next-line:no-any | ||
const skipFrames = options.skipFrames ? options.skipFrames + 1 : 1; | ||
const child = new ChildSpanData(this.trace, /* Trace object */ options.name, /* Span name */ this.span.spanId, /* Parent's span ID */ skipFrames); /* # of frames to skip in stack trace */ | ||
const child = new ChildSpanData(this.trace /* Trace object */, options.name /* Span name */, this.span.spanId /* Parent's span ID */, skipFrames); /* # of frames to skip in stack trace */ | ||
this.children.push(child); | ||
@@ -159,3 +158,3 @@ return child; | ||
traceId: this.trace.traceId, | ||
spans: [this.span] | ||
spans: [this.span], | ||
}); | ||
@@ -170,10 +169,48 @@ } | ||
getTraceContext() { | ||
return ''; | ||
return null; | ||
}, | ||
// tslint:disable-next-line:no-any | ||
addLabel(key, value) { }, | ||
endSpan() { } | ||
endSpan() { }, | ||
}, { type: spanType })); | ||
} | ||
/** | ||
* Helper (and base) class for UntracedRootSpanData. Represents an untraced | ||
* child span. | ||
*/ | ||
class UntracedSpanData { | ||
constructor(traceId) { | ||
this.type = constants_1.SpanType.UNSAMPLED; | ||
this.traceContext = { | ||
traceId, | ||
spanId: randomSpanId(), | ||
options: 0, | ||
}; | ||
} | ||
getTraceContext() { | ||
return this.traceContext; | ||
} | ||
// No-op. | ||
addLabel() { } | ||
// No-op. | ||
endSpan() { } | ||
} | ||
/** | ||
* Represents an "untraced" root span (aka not published). | ||
* For distributed trace context propagation purposes. | ||
*/ | ||
class UntracedRootSpanData extends UntracedSpanData { | ||
constructor() { | ||
super(...arguments); | ||
this.child = null; | ||
} | ||
createChildSpan() { | ||
if (!this.child) { | ||
this.child = new UntracedSpanData(this.traceContext.traceId); | ||
} | ||
return this.child; | ||
} | ||
} | ||
exports.UntracedRootSpanData = UntracedRootSpanData; | ||
/** | ||
* A virtual trace span that indicates that a real child span couldn't be | ||
@@ -185,6 +222,5 @@ * created because the correct root span couldn't be determined. | ||
* A virtual trace span that indicates that a real child span couldn't be | ||
* created because the corresponding root span was disallowed by user | ||
* configuration. | ||
* created because the Trace Agent was disabled. | ||
*/ | ||
exports.UNTRACED_CHILD_SPAN = createPhantomSpanData(constants_1.SpanType.UNTRACED); | ||
exports.DISABLED_CHILD_SPAN = createPhantomSpanData(constants_1.SpanType.DISABLED); | ||
/** | ||
@@ -197,3 +233,3 @@ * A virtual trace span that indicates that a real root span couldn't be | ||
return exports.UNCORRELATED_CHILD_SPAN; | ||
} | ||
}, | ||
}, exports.UNCORRELATED_CHILD_SPAN)); | ||
@@ -204,7 +240,7 @@ /** | ||
*/ | ||
exports.UNTRACED_ROOT_SPAN = Object.freeze(Object.assign({ | ||
exports.DISABLED_ROOT_SPAN = Object.freeze(Object.assign({ | ||
createChildSpan() { | ||
return exports.UNTRACED_CHILD_SPAN; | ||
} | ||
}, exports.UNTRACED_CHILD_SPAN)); | ||
return exports.DISABLED_CHILD_SPAN; | ||
}, | ||
}, exports.DISABLED_CHILD_SPAN)); | ||
//# sourceMappingURL=span-data.js.map |
@@ -18,34 +18,13 @@ /** | ||
import { EventEmitter } from 'events'; | ||
import { OpenCensusPropagation, TracePolicy } from './config'; | ||
import { SpanType } from './constants'; | ||
import { Logger } from './logger'; | ||
import { Func, RootSpan, RootSpanOptions, Span, SpanOptions, Tracer } from './plugin-types'; | ||
import { TracePolicyConfig } from './tracing-policy'; | ||
import { Func, Propagation, RootSpan, RootSpanOptions, Span, SpanOptions, Tracer } from './plugin-types'; | ||
import * as util from './util'; | ||
/** | ||
* An enumeration of the different possible types of behavior when dealing with | ||
* incoming trace context. Requests are still subject to local tracing policy. | ||
*/ | ||
export declare enum TraceContextHeaderBehavior { | ||
/** | ||
* Respect the trace context header if it exists; otherwise, trace the | ||
* request as a new trace. | ||
*/ | ||
DEFAULT = "default", | ||
/** | ||
* Respect the trace context header if it exists; otherwise, treat the | ||
* request as unsampled and don't trace it. | ||
*/ | ||
REQUIRE = "require", | ||
/** | ||
* Trace every request as a new trace, even if trace context exists. | ||
*/ | ||
IGNORE = "ignore" | ||
} | ||
/** | ||
* An interface describing configuration fields read by the StackdriverTracer | ||
* object. This includes fields read by the trace policy. | ||
*/ | ||
export interface StackdriverTracerConfig extends TracePolicyConfig { | ||
export interface StackdriverTracerConfig { | ||
enhancedDatabaseReporting: boolean; | ||
contextHeaderBehavior: TraceContextHeaderBehavior; | ||
rootSpanNameOverride: (path: string) => string; | ||
@@ -56,2 +35,10 @@ spansPerTraceSoftLimit: number; | ||
/** | ||
* A collection of externally-instantiated objects used by StackdriverTracer. | ||
*/ | ||
export interface StackdriverTracerComponents { | ||
logger: Logger; | ||
tracePolicy: TracePolicy; | ||
propagation: OpenCensusPropagation; | ||
} | ||
/** | ||
* StackdriverTracer exposes a number of methods to create trace spans and | ||
@@ -88,7 +75,6 @@ * propagate trace context across asynchronous boundaries. | ||
readonly traceContextUtils: { | ||
encodeAsString: typeof util.generateTraceContext; | ||
decodeFromString: typeof util.parseContextFromHeader; | ||
encodeAsByteArray: typeof util.serializeTraceContext; | ||
decodeFromByteArray: typeof util.deserializeTraceContext; | ||
}; | ||
readonly propagation: Propagation; | ||
private enabled; | ||
@@ -100,2 +86,3 @@ private pluginName; | ||
private policy; | ||
private headerPropagation; | ||
/** | ||
@@ -112,6 +99,7 @@ * Constructs a new StackdriverTracer instance. | ||
* be configured. | ||
* @param logger A logger object. | ||
* @param components An collection of externally-instantiated objects used | ||
* by this instance. | ||
* @private | ||
*/ | ||
enable(config: StackdriverTracerConfig, logger: Logger): void; | ||
enable(config: StackdriverTracerConfig, components: StackdriverTracerComponents): void; | ||
/** | ||
@@ -139,5 +127,9 @@ * Disable this instance. This function is only for internal use and | ||
isRealSpan(span: Span): boolean; | ||
getResponseTraceContext(incomingTraceContext: string | null, isTraced: boolean): string; | ||
getResponseTraceContext(incomingTraceContext: util.TraceContext | null, isTraced: boolean): { | ||
traceId: string; | ||
spanId: string; | ||
options: number; | ||
} | null; | ||
wrap<T>(fn: Func<T>): Func<T>; | ||
wrapEmitter(emitter: EventEmitter): void; | ||
} |
@@ -18,3 +18,2 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const is = require("is"); | ||
const uuid = require("uuid"); | ||
@@ -29,30 +28,2 @@ const cls_1 = require("./cls"); | ||
/** | ||
* An enumeration of the different possible types of behavior when dealing with | ||
* incoming trace context. Requests are still subject to local tracing policy. | ||
*/ | ||
var TraceContextHeaderBehavior; | ||
(function (TraceContextHeaderBehavior) { | ||
/** | ||
* Respect the trace context header if it exists; otherwise, trace the | ||
* request as a new trace. | ||
*/ | ||
TraceContextHeaderBehavior["DEFAULT"] = "default"; | ||
/** | ||
* Respect the trace context header if it exists; otherwise, treat the | ||
* request as unsampled and don't trace it. | ||
*/ | ||
TraceContextHeaderBehavior["REQUIRE"] = "require"; | ||
/** | ||
* Trace every request as a new trace, even if trace context exists. | ||
*/ | ||
TraceContextHeaderBehavior["IGNORE"] = "ignore"; | ||
})(TraceContextHeaderBehavior = exports.TraceContextHeaderBehavior || (exports.TraceContextHeaderBehavior = {})); | ||
/** | ||
* Type guard that returns whether an object is a string or not. | ||
*/ | ||
// tslint:disable-next-line:no-any | ||
function isString(obj) { | ||
return is.string(obj); | ||
} | ||
/** | ||
* StackdriverTracer exposes a number of methods to create trace spans and | ||
@@ -71,7 +42,42 @@ * propagate trace context across asynchronous boundaries. | ||
this.traceContextUtils = { | ||
encodeAsString: util.generateTraceContext, | ||
decodeFromString: util.parseContextFromHeader, | ||
encodeAsByteArray: util.serializeTraceContext, | ||
decodeFromByteArray: util.deserializeTraceContext | ||
decodeFromByteArray: util.deserializeTraceContext, | ||
}; | ||
this.propagation = { | ||
extract: getHeader => { | ||
// If enabled, this.propagationMechanism is non-null. | ||
if (!this.enabled) { | ||
return null; | ||
} | ||
// OpenCensus propagation libraries expect span IDs to be size-16 hex | ||
// strings. In the future it might be worthwhile to change how span IDs | ||
// are stored in this library to avoid excessive base 10<->16 conversions. | ||
const result = this.headerPropagation.extract({ | ||
getHeader: (...args) => { | ||
const result = getHeader(...args); | ||
if (result === null) { | ||
return; // undefined | ||
} | ||
return result; | ||
}, | ||
}); | ||
if (result) { | ||
result.spanId = util.hexToDec(result.spanId); | ||
} | ||
return result; | ||
}, | ||
inject: (setHeader, value) => { | ||
// If enabled, this.propagationMechanism is non-null. | ||
// Also, don't inject a falsey value. | ||
if (!this.enabled || !value) { | ||
return; | ||
} | ||
// Convert back to base-10 span IDs. See the wrapper for `extract` | ||
// for more details. | ||
value = Object.assign({}, value, { | ||
spanId: `0000000000000000${util.decToHex(value.spanId).slice(2)}`.slice(-16), | ||
}); | ||
this.headerPropagation.inject({ setHeader }, value); | ||
}, | ||
}; | ||
this.enabled = false; | ||
@@ -81,2 +87,4 @@ this.logger = null; | ||
this.policy = null; | ||
// The underlying propagation mechanism used by this.propagation. | ||
this.headerPropagation = null; | ||
this.pluginName = name; | ||
@@ -92,9 +100,11 @@ this.pluginNameToLog = this.pluginName ? this.pluginName : 'no-plugin-name'; | ||
* be configured. | ||
* @param logger A logger object. | ||
* @param components An collection of externally-instantiated objects used | ||
* by this instance. | ||
* @private | ||
*/ | ||
enable(config, logger) { | ||
this.logger = logger; | ||
enable(config, components) { | ||
this.config = config; | ||
this.policy = new tracing_policy_1.TracePolicy(config); | ||
this.logger = components.logger; | ||
this.policy = components.tracePolicy; | ||
this.headerPropagation = components.propagation; | ||
this.enabled = true; | ||
@@ -112,3 +122,3 @@ } | ||
// short-circuit out of trace generation logic. | ||
this.policy = tracing_policy_1.TracePolicy.never(); | ||
this.policy = tracing_policy_1.neverTrace(); | ||
this.enabled = false; | ||
@@ -136,3 +146,3 @@ } | ||
if (!this.isActive()) { | ||
return fn(span_data_1.UNTRACED_ROOT_SPAN); | ||
return fn(span_data_1.DISABLED_ROOT_SPAN); | ||
} | ||
@@ -146,39 +156,52 @@ options = options || { name: '' }; | ||
} | ||
// Attempt to read incoming trace context. | ||
const incomingTraceContext = { options: 1 }; | ||
let parsedContext = null; | ||
if (isString(options.traceContext) && | ||
this.config.contextHeaderBehavior !== | ||
TraceContextHeaderBehavior.IGNORE) { | ||
parsedContext = util.parseContextFromHeader(options.traceContext); | ||
} | ||
if (parsedContext) { | ||
if (parsedContext.options === undefined) { | ||
// If there are no incoming option flags, default to 0x1. | ||
parsedContext.options = 1; | ||
// Ensure that the trace context, if it exists, has an options field. | ||
const canonicalizeTraceContext = (traceContext) => { | ||
if (!traceContext) { | ||
return null; | ||
} | ||
Object.assign(incomingTraceContext, parsedContext); | ||
} | ||
else if (this.config.contextHeaderBehavior === | ||
TraceContextHeaderBehavior.REQUIRE) { | ||
incomingTraceContext.options = 0; | ||
} | ||
if (traceContext.options !== undefined) { | ||
return traceContext; | ||
} | ||
return { | ||
traceId: traceContext.traceId, | ||
spanId: traceContext.spanId, | ||
options: 1, | ||
}; | ||
}; | ||
const traceContext = canonicalizeTraceContext(options.traceContext); | ||
// Consult the trace policy. | ||
const locallyAllowed = this.policy.shouldTrace({ | ||
const shouldTrace = this.policy.shouldTrace({ | ||
timestamp: Date.now(), | ||
url: options.url || '', | ||
method: options.method || '' | ||
method: options.method || '', | ||
traceContext, | ||
options, | ||
}); | ||
const remotelyAllowed = !!(incomingTraceContext.options & constants_1.Constants.TRACE_OPTIONS_TRACE_ENABLED); | ||
const traceId = traceContext | ||
? traceContext.traceId | ||
: uuid | ||
.v4() | ||
.split('-') | ||
.join(''); | ||
let rootContext; | ||
// Don't create a root span if the trace policy disallows it. | ||
if (!locallyAllowed || !remotelyAllowed) { | ||
rootContext = span_data_1.UNTRACED_ROOT_SPAN; | ||
// Create an "untraced" root span (one that won't be published) if the | ||
// trace policy disallows it. | ||
if (!shouldTrace) { | ||
rootContext = new span_data_1.UntracedRootSpanData(traceId); | ||
} | ||
else { | ||
// Create a new root span, and invoke fn with it. | ||
const traceId = incomingTraceContext.traceId || (uuid.v4().split('-').join('')); | ||
const parentId = incomingTraceContext.spanId || '0'; | ||
const name = this.config.rootSpanNameOverride(options.name); | ||
rootContext = new span_data_1.RootSpanData({ projectId: '', traceId, spans: [] }, /* Trace object */ name, /* Span name */ parentId, /* Parent's span ID */ options.skipFrames || 0); | ||
rootContext = new span_data_1.RootSpanData( | ||
// Trace object | ||
{ | ||
projectId: '', | ||
traceId, | ||
spans: [], | ||
}, | ||
// Span name | ||
this.config.rootSpanNameOverride(options.name), | ||
// Parent span ID | ||
traceContext ? traceContext.spanId : '0', | ||
// Number of stack frames to skip | ||
options.skipFrames || 0); | ||
} | ||
@@ -191,3 +214,3 @@ return cls_1.cls.get().runWithContext(() => { | ||
if (!this.isActive()) { | ||
return span_data_1.UNTRACED_ROOT_SPAN; | ||
return span_data_1.DISABLED_ROOT_SPAN; | ||
} | ||
@@ -199,4 +222,3 @@ return cls_1.cls.get().getContext(); | ||
const traceContext = this.getCurrentRootSpan().getTraceContext(); | ||
const parsedTraceContext = util.parseContextFromHeader(traceContext); | ||
return parsedTraceContext ? parsedTraceContext.traceId : null; | ||
return traceContext ? traceContext.traceId : null; | ||
} | ||
@@ -222,3 +244,3 @@ getProjectId() { | ||
if (!this.isActive()) { | ||
return span_data_1.UNTRACED_CHILD_SPAN; | ||
return span_data_1.DISABLED_CHILD_SPAN; | ||
} | ||
@@ -243,8 +265,7 @@ options = options || { name: '' }; | ||
// is likely due to userspace task queues or Promise implementations. | ||
this.logger.error(`TraceApi#createChildSpan: [${this.pluginNameToLog}] Creating phantom child span [${options.name}] because the trace with root span [${rootSpan.span.name}] has reached a limit of ${this.config | ||
.spansPerTraceHardLimit} spans. This is likely a memory leak.`); | ||
this.logger.error(`TraceApi#createChildSpan: [${this.pluginNameToLog}] Creating phantom child span [${options.name}] because the trace with root span [${rootSpan.span.name}] has reached a limit of ${this.config.spansPerTraceHardLimit} spans. This is likely a memory leak.`); | ||
this.logger.error([ | ||
'TraceApi#createChildSpan: Please see', | ||
'https://github.com/googleapis/cloud-trace-nodejs/wiki', | ||
'for details and suggested actions.' | ||
'for details and suggested actions.', | ||
].join(' ')); | ||
@@ -261,8 +282,7 @@ return span_data_1.UNCORRELATED_CHILD_SPAN; | ||
// uses the RootSpanData API directly. | ||
this.logger.error(`TraceApi#createChildSpan: [${this.pluginNameToLog}] Adding child span [${options.name}] will cause the trace with root span [${rootSpan.span.name}] to contain more than ${this.config | ||
.spansPerTraceSoftLimit} spans. This is likely a memory leak.`); | ||
this.logger.error(`TraceApi#createChildSpan: [${this.pluginNameToLog}] Adding child span [${options.name}] will cause the trace with root span [${rootSpan.span.name}] to contain more than ${this.config.spansPerTraceSoftLimit} spans. This is likely a memory leak.`); | ||
this.logger.error([ | ||
'TraceApi#createChildSpan: Please see', | ||
'https://github.com/googleapis/cloud-trace-nodejs/wiki', | ||
'for details and suggested actions.' | ||
'for details and suggested actions.', | ||
].join(' ')); | ||
@@ -273,3 +293,3 @@ } | ||
name: options.name, | ||
skipFrames: options.skipFrames ? options.skipFrames + 1 : 1 | ||
skipFrames: options.skipFrames ? options.skipFrames + 1 : 1, | ||
}); | ||
@@ -279,7 +299,9 @@ this.logger.info(`TraceApi#createChildSpan: [${this.pluginNameToLog}] Created child span [${options.name}]`); | ||
} | ||
else if (rootSpan.type === constants_1.SpanType.UNTRACED) { | ||
// Context wasn't lost, but there's no root span, indicating that this | ||
// request should not be traced. | ||
return span_data_1.UNTRACED_CHILD_SPAN; | ||
else if (rootSpan.type === constants_1.SpanType.UNSAMPLED) { | ||
// "Untraced" child spans don't incur a memory penalty. | ||
return rootSpan.createChildSpan(); | ||
} | ||
else if (rootSpan.type === constants_1.SpanType.DISABLED) { | ||
return span_data_1.DISABLED_CHILD_SPAN; | ||
} | ||
else { | ||
@@ -296,10 +318,9 @@ // Context was lost. | ||
if (!this.isActive() || !incomingTraceContext) { | ||
return ''; | ||
return null; | ||
} | ||
const traceContext = util.parseContextFromHeader(incomingTraceContext); | ||
if (!traceContext) { | ||
return ''; | ||
} | ||
traceContext.options = (traceContext.options || 0) & (isTraced ? 1 : 0); | ||
return util.generateTraceContext(traceContext); | ||
return { | ||
traceId: incomingTraceContext.traceId, | ||
spanId: incomingTraceContext.spanId, | ||
options: (incomingTraceContext.options || 0) & (isTraced ? 1 : 0), | ||
}; | ||
} | ||
@@ -306,0 +327,0 @@ wrap(fn) { |
@@ -84,4 +84,4 @@ "use strict"; | ||
*/ | ||
AGENT_DATA: '/agent' | ||
AGENT_DATA: '/agent', | ||
}; | ||
//# sourceMappingURL=trace-labels.js.map |
@@ -16,5 +16,4 @@ /** | ||
*/ | ||
import { Logger } from './logger'; | ||
import { Plugin } from './plugin-types'; | ||
import { StackdriverTracerConfig } from './trace-api'; | ||
import { StackdriverTracerComponents, StackdriverTracerConfig } from './trace-api'; | ||
import { Singleton } from './util'; | ||
@@ -31,6 +30,7 @@ /** | ||
*/ | ||
export interface PluginLoaderConfig extends StackdriverTracerConfig { | ||
export interface PluginLoaderConfig { | ||
plugins: { | ||
[pluginName: string]: string; | ||
}; | ||
tracerConfig: StackdriverTracerConfig; | ||
} | ||
@@ -72,6 +72,7 @@ export interface ModulePluginWrapperOptions { | ||
export declare class ModulePluginWrapper implements PluginWrapper { | ||
private readonly traceConfig; | ||
private static readonly NOT_LOADED; | ||
private readonly unpatchFns; | ||
private readonly logger; | ||
private readonly traceConfig; | ||
private readonly components; | ||
private readonly name; | ||
@@ -85,5 +86,7 @@ private readonly path; | ||
* @param traceConfig Configuration for a StackdriverTracer instance. | ||
* @param tracePolicy The trace policy to apply to a StackdriverTracer | ||
* instance. | ||
* @param logger The logger to use. | ||
*/ | ||
constructor(options: ModulePluginWrapperOptions, traceConfig: StackdriverTracerConfig, logger: Logger); | ||
constructor(options: ModulePluginWrapperOptions, traceConfig: StackdriverTracerConfig, components: StackdriverTracerComponents); | ||
isSupported(version: string): boolean; | ||
@@ -104,3 +107,3 @@ unapplyAll(): void; | ||
private readonly children; | ||
constructor(config: CorePluginWrapperOptions, traceConfig: StackdriverTracerConfig, logger: Logger); | ||
constructor(config: CorePluginWrapperOptions, traceConfig: StackdriverTracerConfig, components: StackdriverTracerComponents); | ||
/** | ||
@@ -135,4 +138,4 @@ * Returns whether the given version of the module is supported by this | ||
export declare class PluginLoader { | ||
static readonly CORE_MODULE = "[core]"; | ||
private readonly logger; | ||
static readonly CORE_MODULE = "[core]"; | ||
private enableRequireHook; | ||
@@ -147,3 +150,3 @@ private readonly pluginMap; | ||
*/ | ||
constructor(config: PluginLoaderConfig, logger: Logger); | ||
constructor(config: PluginLoaderConfig, components: StackdriverTracerComponents); | ||
readonly state: PluginLoaderState; | ||
@@ -177,2 +180,2 @@ /** | ||
} | ||
export declare const pluginLoader: Singleton<PluginLoader, PluginLoaderConfig, Logger>; | ||
export declare const pluginLoader: Singleton<PluginLoader, PluginLoaderConfig, StackdriverTracerComponents>; |
@@ -33,5 +33,8 @@ "use strict"; | ||
* @param traceConfig Configuration for a StackdriverTracer instance. | ||
* @param tracePolicy The trace policy to apply to a StackdriverTracer | ||
* instance. | ||
* @param logger The logger to use. | ||
*/ | ||
constructor(options, traceConfig, logger) { | ||
constructor(options, traceConfig, components) { | ||
this.traceConfig = traceConfig; | ||
this.unpatchFns = []; | ||
@@ -42,6 +45,6 @@ // The exported value of the plugin, or NOT_LOADED if it hasn't been | ||
this.traceApiInstances = []; | ||
this.logger = logger; | ||
this.logger = components.logger; | ||
this.components = components; | ||
this.name = options.name; | ||
this.path = options.path; | ||
this.traceConfig = traceConfig; | ||
} | ||
@@ -108,4 +111,3 @@ isSupported(version) { | ||
else if (patch.intercept) { | ||
exportedValue = | ||
patch.intercept(exportedValue, this.createTraceAgentInstance(file)); | ||
exportedValue = patch.intercept(exportedValue, this.createTraceAgentInstance(file)); | ||
} | ||
@@ -124,3 +126,3 @@ return exportedValue; | ||
const traceApi = new trace_api_1.StackdriverTracer(file); | ||
traceApi.enable(this.traceConfig, this.logger); | ||
traceApi.enable(this.traceConfig, this.components); | ||
this.traceApiInstances.push(traceApi); | ||
@@ -141,5 +143,5 @@ return traceApi; | ||
class CorePluginWrapper { | ||
constructor(config, traceConfig, logger) { | ||
this.logger = logger; | ||
this.children = config.children.map(config => new ModulePluginWrapper(config, traceConfig, logger)); | ||
constructor(config, traceConfig, components) { | ||
this.logger = components.logger; | ||
this.children = config.children.map(config => new ModulePluginWrapper(config, traceConfig, components)); | ||
// Eagerly load core plugins into memory. | ||
@@ -192,4 +194,3 @@ // This prevents issues related to circular dependencies. | ||
*/ | ||
constructor(config, logger) { | ||
this.logger = logger; | ||
constructor(config, components) { | ||
// A map mapping module names to their respective plugins. | ||
@@ -201,2 +202,3 @@ this.pluginMap = new Map(); | ||
this.internalState = PluginLoaderState.NO_HOOK; | ||
this.logger = components.logger; | ||
const nonCoreModules = []; | ||
@@ -210,4 +212,3 @@ // Initialize ALL of the PluginWrapper objects here. | ||
// Core module plugins share a common key. | ||
const coreModule = key === PluginLoader.CORE_MODULE || | ||
builtinModules.indexOf(key) !== -1; | ||
const coreModule = key === PluginLoader.CORE_MODULE || builtinModules.indexOf(key) !== -1; | ||
if (value) { | ||
@@ -220,3 +221,3 @@ // Convert the given string value to a PluginConfigEntry | ||
else { | ||
this.pluginMap.set(key, new ModulePluginWrapper({ name: key, path: value }, config, logger)); | ||
this.pluginMap.set(key, new ModulePluginWrapper({ name: key, path: value }, config.tracerConfig, components)); | ||
} | ||
@@ -227,3 +228,3 @@ nonCoreModules.push(key); | ||
if (coreWrapperConfig.children.length > 0) { | ||
this.pluginMap.set(PluginLoader.CORE_MODULE, new CorePluginWrapper(coreWrapperConfig, config, logger)); | ||
this.pluginMap.set(PluginLoader.CORE_MODULE, new CorePluginWrapper(coreWrapperConfig, config.tracerConfig, components)); | ||
} | ||
@@ -236,4 +237,6 @@ // Define the function that will attach a require hook upon activate. | ||
// TODO(kjin): This should be encapsulated in a class. | ||
this.enableRequireHook = (onRequire) => { | ||
const builtins = this.pluginMap.has(PluginLoader.CORE_MODULE) ? builtinModules : []; | ||
this.enableRequireHook = onRequire => { | ||
const builtins = this.pluginMap.has(PluginLoader.CORE_MODULE) | ||
? builtinModules | ||
: []; | ||
hook(builtins.concat(nonCoreModules), { internals: true }, onRequire); | ||
@@ -287,4 +290,3 @@ }; | ||
if (plugin.isSupported(version)) { | ||
exportedValue = | ||
plugin.applyPlugin(exportedValue, file, version); | ||
exportedValue = plugin.applyPlugin(exportedValue, file, version); | ||
} | ||
@@ -352,3 +354,3 @@ else { | ||
name: parts.slice(0, indexOfFile).join('/'), | ||
file: parts.slice(indexOfFile).join('/') | ||
file: parts.slice(indexOfFile).join('/'), | ||
}; | ||
@@ -387,3 +389,4 @@ } | ||
} | ||
else { // core module | ||
else { | ||
// core module | ||
return process.version.slice(1); // starts with v | ||
@@ -390,0 +393,0 @@ } |
@@ -41,2 +41,4 @@ "use strict"; | ||
const SCOPES = ['https://www.googleapis.com/auth/trace.append']; | ||
/* The API endpoint of the Stackdriver Trace service */ | ||
const TRACE_API_ENDPOINT = 'cloudtrace.googleapis.com'; | ||
class TraceBuffer { | ||
@@ -94,4 +96,5 @@ constructor() { | ||
projectIdRequired: false, | ||
baseUrl: 'https://cloudtrace.googleapis.com/v1', | ||
scopes: SCOPES | ||
apiEndpoint: TRACE_API_ENDPOINT, | ||
baseUrl: `https://${TRACE_API_ENDPOINT}/v1`, | ||
scopes: SCOPES, | ||
}, config); | ||
@@ -145,3 +148,5 @@ this.config = config; | ||
const [hostname, instanceId] = yield Promise.all([ | ||
this.getHostname(), this.getInstanceId(), getProjectIdAndScheduleFlush() | ||
this.getHostname(), | ||
this.getInstanceId(), | ||
getProjectIdAndScheduleFlush(), | ||
]); | ||
@@ -228,3 +233,3 @@ const addDefaultLabel = (key, value) => { | ||
projectId: trace.projectId, | ||
spans: publishableSpans | ||
spans: publishableSpans, | ||
}); | ||
@@ -265,3 +270,3 @@ this.logger.info(`TraceWriter#writeTrace: number of buffered spans = ${this.buffer.getNumSpans()}`); | ||
const afterProjectId = (projectId) => { | ||
flushedTraces.forEach(trace => trace.projectId = projectId); | ||
flushedTraces.forEach(trace => (trace.projectId = projectId)); | ||
this.logger.debug('TraceWriter#flushBuffer: Flushing traces', flushedTraces); | ||
@@ -299,4 +304,3 @@ this.publish(JSON.stringify({ traces: flushedTraces })); | ||
if (err) { | ||
this.logger.error(`TraceWriter#publish: Received error ${statusCode ? `with status code ${statusCode}` : | ||
''} while publishing traces to ${hostname}: ${err}`); | ||
this.logger.error(`TraceWriter#publish: Received error ${statusCode ? `with status code ${statusCode}` : ''} while publishing traces to ${hostname}: ${err}`); | ||
} | ||
@@ -303,0 +307,0 @@ else { |
@@ -0,1 +1,2 @@ | ||
import { RequestDetails, TracePolicy } from './config'; | ||
/** | ||
@@ -17,2 +18,22 @@ * Copyright 2015 Google Inc. All Rights Reserved. | ||
/** | ||
* An enumeration of the different possible types of behavior when dealing with | ||
* incoming trace context. Requests are still subject to local tracing policy. | ||
*/ | ||
export declare enum TraceContextHeaderBehavior { | ||
/** | ||
* Respect the trace context header if it exists; otherwise, trace the | ||
* request as a new trace. | ||
*/ | ||
DEFAULT = "default", | ||
/** | ||
* Respect the trace context header if it exists; otherwise, treat the | ||
* request as unsampled and don't trace it. | ||
*/ | ||
REQUIRE = "require", | ||
/** | ||
* Trace every request as a new trace, even if trace context exists. | ||
*/ | ||
IGNORE = "ignore" | ||
} | ||
/** | ||
* Options for constructing a TracePolicy instance. | ||
@@ -33,2 +54,6 @@ */ | ||
ignoreMethods: string[]; | ||
/** | ||
* A field that controls filtering based on incoming trace context. | ||
*/ | ||
contextHeaderBehavior: TraceContextHeaderBehavior; | ||
} | ||
@@ -38,6 +63,7 @@ /** | ||
*/ | ||
export declare class TracePolicy { | ||
export declare class BuiltinTracePolicy implements TracePolicy { | ||
private readonly sampler; | ||
private readonly urlFilter; | ||
private readonly methodsFilter; | ||
private readonly contextHeaderFilter; | ||
/** | ||
@@ -53,9 +79,5 @@ * Constructs a new TracePolicy instance. | ||
*/ | ||
shouldTrace(options: { | ||
timestamp: number; | ||
url: string; | ||
method: string; | ||
}): boolean; | ||
static always(): TracePolicy; | ||
static never(): TracePolicy; | ||
shouldTrace(options: RequestDetails): boolean; | ||
} | ||
export declare function alwaysTrace(): BuiltinTracePolicy; | ||
export declare function neverTrace(): BuiltinTracePolicy; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const constants_1 = require("./constants"); | ||
/** | ||
@@ -17,3 +19,23 @@ * Copyright 2015 Google Inc. All Rights Reserved. | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** | ||
* An enumeration of the different possible types of behavior when dealing with | ||
* incoming trace context. Requests are still subject to local tracing policy. | ||
*/ | ||
var TraceContextHeaderBehavior; | ||
(function (TraceContextHeaderBehavior) { | ||
/** | ||
* Respect the trace context header if it exists; otherwise, trace the | ||
* request as a new trace. | ||
*/ | ||
TraceContextHeaderBehavior["DEFAULT"] = "default"; | ||
/** | ||
* Respect the trace context header if it exists; otherwise, treat the | ||
* request as unsampled and don't trace it. | ||
*/ | ||
TraceContextHeaderBehavior["REQUIRE"] = "require"; | ||
/** | ||
* Trace every request as a new trace, even if trace context exists. | ||
*/ | ||
TraceContextHeaderBehavior["IGNORE"] = "ignore"; | ||
})(TraceContextHeaderBehavior = exports.TraceContextHeaderBehavior || (exports.TraceContextHeaderBehavior = {})); | ||
class Sampler { | ||
@@ -40,5 +62,5 @@ constructor(samplesPerSecond) { | ||
shouldTrace(url) { | ||
return !this.filterUrls.some((candidate) => { | ||
return (typeof candidate === 'string' && candidate === url) || | ||
!!url.match(candidate); | ||
return !this.filterUrls.some(candidate => { | ||
return ((typeof candidate === 'string' && candidate === url) || | ||
!!url.match(candidate)); | ||
}); | ||
@@ -52,11 +74,33 @@ } | ||
shouldTrace(method) { | ||
return !this.filterMethods.some((candidate) => { | ||
return (candidate.toLowerCase() === method.toLowerCase()); | ||
return !this.filterMethods.some(candidate => { | ||
return candidate.toLowerCase() === method.toLowerCase(); | ||
}); | ||
} | ||
} | ||
class ContextHeaderFilter { | ||
constructor(contextHeaderBehavior) { | ||
this.contextHeaderBehavior = contextHeaderBehavior; | ||
} | ||
shouldTrace(header) { | ||
switch (this.contextHeaderBehavior) { | ||
case TraceContextHeaderBehavior.IGNORE: { | ||
return true; | ||
} | ||
case TraceContextHeaderBehavior.REQUIRE: { | ||
// There must be an incoming header, and its LSB must be 1. | ||
return !!(header && header.options & constants_1.Constants.TRACE_OPTIONS_TRACE_ENABLED); | ||
} | ||
default: { | ||
// TraceContextHeaderBehavior.DEFAULT | ||
// If there is a header, its LSB must be 1. Otherwise, we assume that | ||
// it would be 1. | ||
return !!(!header || header.options & constants_1.Constants.TRACE_OPTIONS_TRACE_ENABLED); | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* A class that makes decisions about whether a trace should be created. | ||
*/ | ||
class TracePolicy { | ||
class BuiltinTracePolicy { | ||
/** | ||
@@ -88,2 +132,8 @@ * Constructs a new TracePolicy instance. | ||
} | ||
if (config.contextHeaderBehavior === TraceContextHeaderBehavior.IGNORE) { | ||
this.contextHeaderFilter = { shouldTrace: () => true }; | ||
} | ||
else { | ||
this.contextHeaderFilter = new ContextHeaderFilter(config.contextHeaderBehavior); | ||
} | ||
} | ||
@@ -96,14 +146,27 @@ /** | ||
shouldTrace(options) { | ||
return this.sampler.shouldTrace(options.timestamp) && | ||
this.urlFilter.shouldTrace(options.url) && | ||
this.methodsFilter.shouldTrace(options.method); | ||
return (this.urlFilter.shouldTrace(options.url) && | ||
this.methodsFilter.shouldTrace(options.method) && | ||
this.contextHeaderFilter.shouldTrace(options.traceContext) && | ||
this.sampler.shouldTrace(options.timestamp)); | ||
} | ||
static always() { | ||
return new TracePolicy({ samplingRate: 0, ignoreUrls: [], ignoreMethods: [] }); | ||
} | ||
static never() { | ||
return new TracePolicy({ samplingRate: -1, ignoreUrls: [], ignoreMethods: [] }); | ||
} | ||
} | ||
exports.TracePolicy = TracePolicy; | ||
exports.BuiltinTracePolicy = BuiltinTracePolicy; | ||
function alwaysTrace() { | ||
return new BuiltinTracePolicy({ | ||
samplingRate: 0, | ||
ignoreUrls: [], | ||
ignoreMethods: [], | ||
contextHeaderBehavior: TraceContextHeaderBehavior.DEFAULT, | ||
}); | ||
} | ||
exports.alwaysTrace = alwaysTrace; | ||
function neverTrace() { | ||
return new BuiltinTracePolicy({ | ||
samplingRate: -1, | ||
ignoreUrls: [], | ||
ignoreMethods: [], | ||
contextHeaderBehavior: TraceContextHeaderBehavior.DEFAULT, | ||
}); | ||
} | ||
exports.neverTrace = neverTrace; | ||
//# sourceMappingURL=tracing-policy.js.map |
@@ -16,15 +16,23 @@ /** | ||
*/ | ||
import { CLSMechanism } from './config'; | ||
import { TraceCLSConfig } from './cls'; | ||
import { OpenCensusPropagation, TracePolicy } from './config'; | ||
import { StackdriverTracer } from './trace-api'; | ||
import { PluginLoaderConfig } from './trace-plugin-loader'; | ||
import { TraceWriterConfig } from './trace-writer'; | ||
import { Component, Singleton } from './util'; | ||
export interface TopLevelConfig { | ||
import { TracePolicyConfig } from './tracing-policy'; | ||
import { Component, Forceable, Singleton } from './util'; | ||
export declare type TopLevelConfig = Forceable<{ | ||
enabled: boolean; | ||
logLevel: number; | ||
clsMechanism: CLSMechanism; | ||
} | ||
export declare type NormalizedConfig = ((TraceWriterConfig & PluginLoaderConfig & TopLevelConfig) | { | ||
clsConfig: Forceable<TraceCLSConfig>; | ||
writerConfig: Forceable<TraceWriterConfig>; | ||
pluginLoaderConfig: Forceable<PluginLoaderConfig>; | ||
tracePolicyConfig: TracePolicyConfig; | ||
overrides: { | ||
tracePolicy?: TracePolicy; | ||
propagation?: OpenCensusPropagation; | ||
}; | ||
}> | { | ||
enabled: false; | ||
}); | ||
}; | ||
/** | ||
@@ -44,3 +52,3 @@ * A class that represents automatic tracing. | ||
*/ | ||
constructor(config: NormalizedConfig, traceAgent: StackdriverTracer); | ||
constructor(config: TopLevelConfig, traceAgent: StackdriverTracer); | ||
/** | ||
@@ -65,4 +73,2 @@ * Logs an error message detailing the list of modules that were loaded before | ||
} | ||
export declare const tracing: Singleton<Tracing, { | ||
enabled: false; | ||
} | (TraceWriterConfig & PluginLoaderConfig & TopLevelConfig), StackdriverTracer>; | ||
export declare const tracing: Singleton<Tracing, TopLevelConfig, StackdriverTracer>; |
@@ -18,2 +18,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const propagation_stackdriver_1 = require("@opencensus/propagation-stackdriver"); | ||
const path = require("path"); | ||
@@ -24,2 +25,3 @@ const cls_1 = require("./cls"); | ||
const trace_writer_1 = require("./trace-writer"); | ||
const tracing_policy_1 = require("./tracing-policy"); | ||
const util_1 = require("./util"); | ||
@@ -47,3 +49,6 @@ /** | ||
} | ||
this.logger = new logger_1.Logger({ level: defaultLevels[logLevel], tag: '@google-cloud/trace-agent' }); | ||
this.logger = new logger_1.Logger({ | ||
level: defaultLevels[logLevel], | ||
tag: '@google-cloud/trace-agent', | ||
}); | ||
} | ||
@@ -62,3 +67,4 @@ /** | ||
const moduleName = util_1.packageNameFromPath(filesLoadedBeforeTrace[i]); | ||
if (moduleName && moduleName !== traceModuleName && | ||
if (moduleName && | ||
moduleName !== traceModuleName && | ||
modulesLoadedBeforeTrace.indexOf(moduleName) === -1) { | ||
@@ -80,9 +86,5 @@ modulesLoadedBeforeTrace.push(moduleName); | ||
// Initialize context propagation mechanism configuration. | ||
const clsConfig = { | ||
mechanism: this.config.clsMechanism, | ||
[util_1.FORCE_NEW]: this.config[util_1.FORCE_NEW] | ||
}; | ||
try { | ||
trace_writer_1.traceWriter.create(this.config, this.logger); | ||
cls_1.cls.create(clsConfig, this.logger); | ||
trace_writer_1.traceWriter.create(this.config.writerConfig, this.logger); | ||
cls_1.cls.create(this.config.clsConfig, this.logger); | ||
} | ||
@@ -94,3 +96,6 @@ catch (e) { | ||
} | ||
trace_writer_1.traceWriter.get().initialize().catch((err) => { | ||
trace_writer_1.traceWriter | ||
.get() | ||
.initialize() | ||
.catch(err => { | ||
this.logger.error('StackdriverTracer#start: Disabling the Trace Agent for the', `following reason: ${err.message}`); | ||
@@ -100,6 +105,12 @@ this.disable(); | ||
cls_1.cls.get().enable(); | ||
this.traceAgent.enable(this.config, this.logger); | ||
trace_plugin_loader_1.pluginLoader.create(this.config, this.logger).activate(); | ||
if (typeof this.config.projectId !== 'string' && | ||
typeof this.config.projectId !== 'undefined') { | ||
const tracePolicy = this.config.overrides.tracePolicy || | ||
new tracing_policy_1.BuiltinTracePolicy(this.config.tracePolicyConfig); | ||
const propagation = this.config.overrides.propagation || new propagation_stackdriver_1.StackdriverFormat(); | ||
const tracerComponents = { logger: this.logger, tracePolicy, propagation }; | ||
this.traceAgent.enable(this.config.pluginLoaderConfig.tracerConfig, tracerComponents); | ||
trace_plugin_loader_1.pluginLoader | ||
.create(this.config.pluginLoaderConfig, tracerComponents) | ||
.activate(); | ||
if (typeof this.config.writerConfig.projectId !== 'string' && | ||
typeof this.config.writerConfig.projectId !== 'undefined') { | ||
this.logger.error('StackdriverTracer#start: config.projectId, if provided, must be a string.', 'Disabling trace agent.'); | ||
@@ -106,0 +117,0 @@ this.disable(); |
@@ -1,17 +0,4 @@ | ||
/** | ||
* Copyright 2015 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/// <reference types="node" /> | ||
declare const hexToDec: (input: string) => string, decToHex: (input: string) => string; | ||
export { hexToDec, decToHex }; | ||
export declare const kSingleton: unique symbol; | ||
@@ -44,6 +31,6 @@ /** | ||
}; | ||
export declare type Component = { | ||
export interface Component { | ||
enable(): void; | ||
disable(): void; | ||
}; | ||
} | ||
/** | ||
@@ -64,2 +51,8 @@ * A class that provides access to a singleton. | ||
/** | ||
* Returns the last parameter that is not null, undefined, or NaN. | ||
* @param defaultValue The first parameter. This must not be null/undefined/NaN. | ||
* @param otherValues Other parameters, which may be null/undefined/NaN. | ||
*/ | ||
export declare function lastOf<T>(defaultValue: T, ...otherValues: Array<T | null | undefined>): T; | ||
/** | ||
* Truncates the provided `string` to be at most `length` bytes | ||
@@ -66,0 +59,0 @@ * after utf8 encoding and the appending of '...'. |
"use strict"; | ||
var _a; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
"use strict"; | ||
/** | ||
@@ -17,7 +20,7 @@ * Copyright 2015 Google Inc. All Rights Reserved. | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var _a; | ||
"use strict"; | ||
const path = require("path"); | ||
const { hexToDec, decToHex } = require('hex2dec'); | ||
const sourceMapSupport = require("source-map-support"); | ||
const { hexToDec, decToHex, } = require('hex2dec'); | ||
exports.hexToDec = hexToDec; | ||
exports.decToHex = decToHex; | ||
// This symbol must be exported (for now). | ||
@@ -65,2 +68,20 @@ // See: https://github.com/Microsoft/TypeScript/issues/20080 | ||
/** | ||
* Returns the last parameter that is not null, undefined, or NaN. | ||
* @param defaultValue The first parameter. This must not be null/undefined/NaN. | ||
* @param otherValues Other parameters, which may be null/undefined/NaN. | ||
*/ | ||
function lastOf(defaultValue, ...otherValues) { | ||
for (let i = otherValues.length - 1; i >= 0; i--) { | ||
// tslint:disable:no-any | ||
if (otherValues[i] !== null && | ||
otherValues[i] !== undefined && | ||
(typeof otherValues[i] !== 'number' || !isNaN(otherValues[i]))) { | ||
return otherValues[i]; | ||
} | ||
// tslint:enable:no-any | ||
} | ||
return defaultValue; | ||
} | ||
exports.lastOf = lastOf; | ||
/** | ||
* Truncates the provided `string` to be at most `length` bytes | ||
@@ -87,4 +108,8 @@ * after utf8 encoding and the appending of '...'. | ||
const moduleRegex = new RegExp([ | ||
'.*?node_modules(?!.*node_modules)\\', '(@[^\\', ']*\\', '[^\\', ']*|[^\\', | ||
']*).*' | ||
'.*?node_modules(?!.*node_modules)\\', | ||
'(@[^\\', | ||
']*\\', | ||
'[^\\', | ||
']*|[^\\', | ||
']*).*', | ||
].join(path.sep)); | ||
@@ -106,3 +131,5 @@ /** | ||
const matches = str.match(/^([0-9a-fA-F]+)(?:\/([0-9]+))(?:;o=(.*))?/); | ||
if (!matches || matches.length !== 4 || matches[0] !== str || | ||
if (!matches || | ||
matches.length !== 4 || | ||
matches[0] !== str || | ||
(matches[2] && isNaN(Number(matches[2])))) { | ||
@@ -114,3 +141,3 @@ return null; | ||
spanId: matches[2], | ||
options: isNaN(Number(matches[3])) ? undefined : Number(matches[3]) | ||
options: isNaN(Number(matches[3])) ? undefined : Number(matches[3]), | ||
}; | ||
@@ -170,6 +197,5 @@ } | ||
const origPrepare = Error.prepareStackTrace; | ||
Error.prepareStackTrace = | ||
(error, structured) => { | ||
return structured; | ||
}; | ||
Error.prepareStackTrace = (error, structured) => { | ||
return structured.map(sourceMapSupport.wrapCallSite); | ||
}; | ||
const e = {}; | ||
@@ -187,5 +213,5 @@ Error.captureStackTrace(e, constructorOpt); | ||
const methodName = callSite.getMethodName(); | ||
const name = (methodName && functionName) ? | ||
functionName + ' [as ' + methodName + ']' : | ||
functionName || methodName || '<anonymous function>'; | ||
const name = methodName && functionName | ||
? functionName + ' [as ' + methodName + ']' | ||
: functionName || methodName || '<anonymous function>'; | ||
const stackFrame = { | ||
@@ -195,3 +221,3 @@ method_name: name, | ||
line_number: callSite.getLineNumber() || undefined, | ||
column_number: callSite.getColumnNumber() || undefined | ||
column_number: callSite.getColumnNumber() || undefined, | ||
}; | ||
@@ -250,4 +276,6 @@ stackFrames.push(stackFrame); | ||
// Check version and field numbers. | ||
if (buffer.readUInt8(0) !== 0 || buffer.readUInt8(1) !== 0 || | ||
buffer.readUInt8(18) !== 1 || buffer.readUInt8(27) !== 2) { | ||
if (buffer.readUInt8(0) !== 0 || | ||
buffer.readUInt8(1) !== 0 || | ||
buffer.readUInt8(18) !== 1 || | ||
buffer.readUInt8(27) !== 2) { | ||
return null; | ||
@@ -254,0 +282,0 @@ } |
{ | ||
"name": "@google-cloud/trace-agent", | ||
"version": "3.6.1", | ||
"version": "4.0.0", | ||
"description": "Node.js Support for StackDriver Trace", | ||
@@ -14,7 +14,5 @@ "main": "build/src/index.js", | ||
"system-test": "npm run script decrypt-service-account-credentials run-system-tests", | ||
"changelog": "./bin/run-changelog.sh", | ||
"check-install": "npm run script check-install", | ||
"get-plugin-types": "npm run script get-plugin-types", | ||
"coverage": "npm run script run-unit-tests-with-coverage report-coverage", | ||
"bump": "./bin/run-bump.sh", | ||
"check": "gts check", | ||
@@ -51,3 +49,3 @@ "clean": "rimraf build/src", | ||
"engines": { | ||
"node": ">=6" | ||
"node": ">=8.10.0" | ||
}, | ||
@@ -66,7 +64,5 @@ "devDependencies": { | ||
"@types/mongoose": "^5.3.26", | ||
"@types/ncp": "^2.0.1", | ||
"@types/nock": "^10.0.0", | ||
"@types/node": "~10.7.2", | ||
"@types/once": "^1.4.0", | ||
"@types/pify": "^3.0.0", | ||
"@types/proxyquire": "^1.3.28", | ||
@@ -76,33 +72,31 @@ "@types/request": "^2.48.1", | ||
"@types/shimmer": "^1.0.1", | ||
"@types/source-map-support": "^0.5.0", | ||
"@types/tmp": "0.1.0", | ||
"@types/uuid": "^3.4.3", | ||
"axios": "^0.18.0", | ||
"changelog-maker": "^2.2.2", | ||
"axios": "^0.19.0", | ||
"codecov": "^3.0.0", | ||
"cpy": "^7.2.0", | ||
"express": "^4.15.2", | ||
"glob": "^7.0.3", | ||
"grpc": "1.20.2", | ||
"gts": "^0.9.0", | ||
"grpc": "1.21.1", | ||
"gts": "^1.0.0", | ||
"intelli-espower-loader": "^1.0.1", | ||
"js-green-licenses": "^0.5.0", | ||
"jshint": "^2.9.1", | ||
"js-green-licenses": "^1.0.0", | ||
"linkinator": "^1.1.2", | ||
"mocha": "^6.0.0", | ||
"ncp": "^2.0.0", | ||
"nock": "^10.0.0", | ||
"nyc": "^14.0.0", | ||
"once": "^1.4.0", | ||
"pify": "^4.0.0", | ||
"retry-axios": "^0.5.0", | ||
"retry-axios": "^1.0.0", | ||
"rimraf": "^2.6.2", | ||
"source-map-support": "^0.5.6", | ||
"standard-version": "^5.0.0", | ||
"teeny-request": "^3.11.1", | ||
"standard-version": "^6.0.0", | ||
"teeny-request": "^4.0.0", | ||
"timekeeper": "^2.0.0", | ||
"tmp": "0.1.0", | ||
"ts-node": "^8.0.0", | ||
"typescript": "~3.4.0" | ||
"typescript": "~3.5.1" | ||
}, | ||
"dependencies": { | ||
"@google-cloud/common": "^0.32.1", | ||
"@google-cloud/common": "^2.0.0", | ||
"@opencensus/propagation-stackdriver": "0.0.13", | ||
"builtin-modules": "^3.0.0", | ||
@@ -112,3 +106,3 @@ "console-log-level": "^1.4.0", | ||
"extend": "^3.0.0", | ||
"gcp-metadata": "^1.0.0", | ||
"gcp-metadata": "^2.0.0", | ||
"hex2dec": "^1.0.1", | ||
@@ -119,2 +113,3 @@ "is": "^3.2.0", | ||
"semver": "^6.0.0", | ||
"source-map-support": "^0.5.12", | ||
"shimmer": "^1.2.0", | ||
@@ -121,0 +116,0 @@ "uuid": "^3.0.1" |
@@ -163,3 +163,3 @@ # Stackdriver Trace Agent for Node.js | ||
The way we trace modules we does not support bundled server code. Bundlers like webpack or @zeit/ncc will not work. | ||
The way we trace modules does not support bundled server code. Bundlers like webpack or @zeit/ncc will not work. | ||
@@ -166,0 +166,0 @@ ## Contributing changes |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
319845
43
7045
1
15
+ Addedsource-map-support@^0.5.12
+ Added@google-cloud/common@2.4.0(transitive)
+ Added@google-cloud/projectify@1.0.4(transitive)
+ Added@google-cloud/promisify@1.0.4(transitive)
+ Added@opencensus/core@0.0.13(transitive)
+ Added@opencensus/propagation-stackdriver@0.0.13(transitive)
+ Added@tootallnate/once@1.1.2(transitive)
+ Addedagent-base@6.0.2(transitive)
+ Addedbuffer-from@1.1.2(transitive)
+ Addedgaxios@2.3.4(transitive)
+ Addedgcp-metadata@2.0.43.5.0(transitive)
+ Addedgoogle-auth-library@5.10.1(transitive)
+ Addedgoogle-p12-pem@2.0.5(transitive)
+ Addedgtoken@4.1.4(transitive)
+ Addedhttp-proxy-agent@4.0.1(transitive)
+ Addedhttps-proxy-agent@5.0.1(transitive)
+ Addedis-stream@2.0.1(transitive)
+ Addedjwa@2.0.0(transitive)
+ Addedjws@4.0.0(transitive)
+ Addedlog-driver@1.2.7(transitive)
+ Addedsource-map@0.6.1(transitive)
+ Addedsource-map-support@0.5.21(transitive)
+ Addedstream-events@1.0.5(transitive)
+ Addedstubs@3.0.0(transitive)
+ Addedteeny-request@6.0.3(transitive)
+ Addeduuid@7.0.3(transitive)
- Removed@google-cloud/common@0.32.1(transitive)
- Removed@google-cloud/projectify@0.3.3(transitive)
- Removed@google-cloud/promisify@0.4.0(transitive)
- Removed@types/caseless@0.12.5(transitive)
- Removed@types/node@22.5.5(transitive)
- Removed@types/request@2.48.12(transitive)
- Removed@types/tough-cookie@4.0.5(transitive)
- Removedagent-base@4.3.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removeddebug@3.2.7(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedes6-promise@4.2.8(transitive)
- Removedes6-promisify@5.0.0(transitive)
- Removedform-data@2.5.1(transitive)
- Removedgaxios@1.8.4(transitive)
- Removedgcp-metadata@1.0.0(transitive)
- Removedgoogle-auth-library@3.1.2(transitive)
- Removedgoogle-p12-pem@1.0.5(transitive)
- Removedgtoken@2.3.3(transitive)
- Removedhttps-proxy-agent@2.2.4(transitive)
- Removedjwa@1.4.1(transitive)
- Removedjws@3.2.2(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedpify@4.0.1(transitive)
- Removedteeny-request@3.11.3(transitive)
- Removedundici-types@6.19.8(transitive)
Updated@google-cloud/common@^2.0.0
Updatedgcp-metadata@^2.0.0