Merge branch 'main' of github.com:open-telemetry/opentelemetry-js into config-yml
This commit is contained in:
commit
b158b36f29
|
|
@ -10,6 +10,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
|
|||
|
||||
### :rocket: Features
|
||||
|
||||
* feat(sampler-composite): Added experimental implementations of draft composite sampling spec [#5839](https://github.com/open-telemetry/opentelemetry-js/pull/5839) @anuraaga
|
||||
* feat(opentelemetry-configuration): Parse of Configuration File [#5875](https://github.com/open-telemetry/opentelemetry-js/pull/5875) @maryliag
|
||||
|
||||
### :bug: Bug Fixes
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
build
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
"env": {
|
||||
"mocha": true,
|
||||
"commonjs": true,
|
||||
"shared-node-browser": true
|
||||
},
|
||||
...require('../../../eslint.base.js')
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
# OpenTelemetry Composite Sampling
|
||||
|
||||
[![NPM Published Version][npm-img]][npm-url]
|
||||
[![Apache License][license-image]][license-image]
|
||||
|
||||
**Note: This is an experimental package under active development. New releases may include breaking changes.**
|
||||
|
||||
This package provides implementations of composite samplers that propagate sampling information across a trace.
|
||||
This implements the [experimental specification][probability-sampling].
|
||||
|
||||
Currently `ComposableRuleBased` and `ComposableAnnotating` are not implemented.
|
||||
|
||||
## Quick Start
|
||||
|
||||
To get started you will need to install a compatible OpenTelemetry SDK.
|
||||
|
||||
### Samplers
|
||||
|
||||
This module exports samplers that follow the general behavior of the standard SDK samplers, but ensuring
|
||||
it is consistent across a trace by using the tracestate header. Notably, the tracestate can be examined
|
||||
in exported spans to reconstruct population metrics.
|
||||
|
||||
```typescript
|
||||
import {
|
||||
createCompositeSampler,
|
||||
createComposableAlwaysOffSampler,
|
||||
createComposableAlwaysOnSampler,
|
||||
createComposableParentThresholdSampler,
|
||||
createComposableTraceIDRatioBasedSampler,
|
||||
} from '@opentelemetry/sampler-composite';
|
||||
|
||||
// never sample
|
||||
const sampler = createCompositeSampler(createComposableAlwaysOffSampler());
|
||||
// always sample
|
||||
const sampler = createCompositeSampler(createComposableAlwaysOnSampler());
|
||||
// follow the parent, or otherwise sample with a probability if root
|
||||
const sampler = createCompositeSampler(
|
||||
createComposableParentThresholdSampler(createComposableTraceIDRatioBasedSampler(0.3)));
|
||||
```
|
||||
|
||||
## Useful links
|
||||
|
||||
- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
|
||||
- For more about OpenTelemetry JavaScript: <https://github.com/open-telemetry/opentelemetry-js>
|
||||
- For help or feedback on this project, join us in [GitHub Discussions][discussions-url]
|
||||
|
||||
## License
|
||||
|
||||
Apache 2.0 - See [LICENSE][license-url] for more information.
|
||||
|
||||
[discussions-url]: https://github.com/open-telemetry/opentelemetry-js/discussions
|
||||
[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/main/LICENSE
|
||||
[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
|
||||
[npm-url]: https://www.npmjs.com/package/@opentelemetry/sampler-composite
|
||||
[npm-img]: https://badge.fury.io/js/%40opentelemetry%sampler-composite.svg
|
||||
|
||||
[probability-sampling]: https://opentelemetry.io/docs/specs/otel/trace/tracestate-probability-sampling/
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"name": "@opentelemetry/sampler-composite",
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"version": "0.205.0",
|
||||
"description": "Composite samplers for OpenTelemetry tracing",
|
||||
"module": "build/esm/index.js",
|
||||
"esnext": "build/esnext/index.js",
|
||||
"types": "build/src/index.d.ts",
|
||||
"main": "build/src/index.js",
|
||||
"repository": "open-telemetry/opentelemetry-js",
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run compile",
|
||||
"compile": "tsc --build",
|
||||
"clean": "tsc --build --clean",
|
||||
"test": "nyc mocha 'test/**/*.test.ts'",
|
||||
"tdd": "npm run test -- --watch-extensions ts --watch",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint . --ext .ts --fix",
|
||||
"version": "node ../../../scripts/version-update.js",
|
||||
"watch": "tsc --build --watch",
|
||||
"precompile": "lerna run version --scope @opentelemetry/sampler-composite --include-dependencies",
|
||||
"prewatch": "npm run precompile",
|
||||
"peer-api-check": "node ../../../scripts/peer-api-check.js",
|
||||
"align-api-deps": "node ../../../scripts/align-api-deps.js"
|
||||
},
|
||||
"keywords": [
|
||||
"opentelemetry",
|
||||
"nodejs",
|
||||
"sampling",
|
||||
"tracing"
|
||||
],
|
||||
"author": "OpenTelemetry Authors",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
"files": [
|
||||
"build/esm/**/*.js",
|
||||
"build/esm/**/*.js.map",
|
||||
"build/esm/**/*.d.ts",
|
||||
"build/esnext/**/*.js",
|
||||
"build/esnext/**/*.js.map",
|
||||
"build/esnext/**/*.d.ts",
|
||||
"build/src/**/*.js",
|
||||
"build/src/**/*.js.map",
|
||||
"build/src/**/*.d.ts",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/node": "18.6.5",
|
||||
"lerna": "6.6.2",
|
||||
"mocha": "11.1.0",
|
||||
"nyc": "17.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/sdk-trace-base": "2.0.1"
|
||||
},
|
||||
"homepage": "https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/sampler-composite",
|
||||
"sideEffects": false
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
import type { ComposableSampler, SamplingIntent } from './types';
|
||||
import { INVALID_THRESHOLD } from './util';
|
||||
|
||||
const intent: SamplingIntent = {
|
||||
threshold: INVALID_THRESHOLD,
|
||||
thresholdReliable: false,
|
||||
};
|
||||
|
||||
class ComposableAlwaysOffSampler implements ComposableSampler {
|
||||
getSamplingIntent(): SamplingIntent {
|
||||
return intent;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return 'ComposableAlwaysOffSampler';
|
||||
}
|
||||
}
|
||||
|
||||
const _sampler = new ComposableAlwaysOffSampler();
|
||||
|
||||
/**
|
||||
* Returns a composable sampler that does not sample any span.
|
||||
*/
|
||||
export function createComposableAlwaysOffSampler(): ComposableSampler {
|
||||
return _sampler;
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
import type { ComposableSampler, SamplingIntent } from './types';
|
||||
import { MIN_THRESHOLD } from './util';
|
||||
|
||||
const intent: SamplingIntent = {
|
||||
threshold: MIN_THRESHOLD,
|
||||
thresholdReliable: true,
|
||||
};
|
||||
|
||||
class ComposableAlwaysOnSampler implements ComposableSampler {
|
||||
getSamplingIntent(): SamplingIntent {
|
||||
return intent;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return 'ComposableAlwaysOnSampler';
|
||||
}
|
||||
}
|
||||
|
||||
const _sampler = new ComposableAlwaysOnSampler();
|
||||
|
||||
/**
|
||||
* Returns a composable sampler that samples all span.
|
||||
*/
|
||||
export function createComposableAlwaysOnSampler(): ComposableSampler {
|
||||
return _sampler;
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
import {
|
||||
Context,
|
||||
SpanKind,
|
||||
Attributes,
|
||||
Link,
|
||||
TraceState,
|
||||
trace,
|
||||
} from '@opentelemetry/api';
|
||||
import { TraceState as CoreTraceState } from '@opentelemetry/core';
|
||||
import {
|
||||
Sampler,
|
||||
SamplingDecision,
|
||||
SamplingResult,
|
||||
} from '@opentelemetry/sdk-trace-base';
|
||||
import { ComposableSampler } from './types';
|
||||
import { parseOtelTraceState, serializeTraceState } from './tracestate';
|
||||
import {
|
||||
INVALID_THRESHOLD,
|
||||
isValidRandomValue,
|
||||
isValidThreshold,
|
||||
} from './util';
|
||||
|
||||
class CompositeSampler implements Sampler {
|
||||
constructor(private readonly delegate: ComposableSampler) {}
|
||||
|
||||
shouldSample(
|
||||
context: Context,
|
||||
traceId: string,
|
||||
spanName: string,
|
||||
spanKind: SpanKind,
|
||||
attributes: Attributes,
|
||||
links: Link[]
|
||||
): SamplingResult {
|
||||
const spanContext = trace.getSpanContext(context);
|
||||
|
||||
const traceState = spanContext?.traceState;
|
||||
let otTraceState = parseOtelTraceState(traceState);
|
||||
|
||||
const intent = this.delegate.getSamplingIntent(
|
||||
context,
|
||||
traceId,
|
||||
spanName,
|
||||
spanKind,
|
||||
attributes,
|
||||
links
|
||||
);
|
||||
|
||||
let adjustedCountCorrect = false;
|
||||
let sampled = false;
|
||||
if (isValidThreshold(intent.threshold)) {
|
||||
adjustedCountCorrect = intent.thresholdReliable;
|
||||
let randomness: bigint;
|
||||
if (isValidRandomValue(otTraceState.randomValue)) {
|
||||
randomness = otTraceState.randomValue;
|
||||
} else {
|
||||
// Use last 56 bits of trace_id as randomness.
|
||||
randomness = BigInt(`0x${traceId.slice(-14)}`);
|
||||
}
|
||||
sampled = intent.threshold <= randomness;
|
||||
}
|
||||
|
||||
const decision = sampled
|
||||
? SamplingDecision.RECORD_AND_SAMPLED
|
||||
: SamplingDecision.NOT_RECORD;
|
||||
if (sampled && adjustedCountCorrect) {
|
||||
otTraceState = {
|
||||
...otTraceState,
|
||||
threshold: intent.threshold,
|
||||
};
|
||||
} else {
|
||||
otTraceState = {
|
||||
...otTraceState,
|
||||
threshold: INVALID_THRESHOLD,
|
||||
};
|
||||
}
|
||||
|
||||
const otts = serializeTraceState(otTraceState);
|
||||
|
||||
let newTraceState: TraceState | undefined;
|
||||
if (traceState) {
|
||||
newTraceState = traceState;
|
||||
if (intent.updateTraceState) {
|
||||
newTraceState = intent.updateTraceState(newTraceState);
|
||||
}
|
||||
}
|
||||
if (otts) {
|
||||
if (!newTraceState) {
|
||||
newTraceState = new CoreTraceState();
|
||||
}
|
||||
newTraceState = newTraceState.set('ot', otts);
|
||||
}
|
||||
|
||||
return {
|
||||
decision,
|
||||
attributes: intent.attributes,
|
||||
traceState: newTraceState,
|
||||
};
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.delegate.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a composite sampler that uses a composable sampler to make its
|
||||
* sampling decisions while handling tracestate.
|
||||
*/
|
||||
export function createCompositeSampler(delegate: ComposableSampler): Sampler {
|
||||
return new CompositeSampler(delegate);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
export { createComposableAlwaysOffSampler } from './alwaysoff';
|
||||
export { createComposableAlwaysOnSampler } from './alwayson';
|
||||
export { createComposableTraceIDRatioBasedSampler } from './traceidratio';
|
||||
export { createComposableParentThresholdSampler } from './parentthreshold';
|
||||
export { createCompositeSampler } from './composite';
|
||||
export type { ComposableSampler, SamplingIntent } from './types';
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import {
|
||||
Attributes,
|
||||
Context,
|
||||
isSpanContextValid,
|
||||
Link,
|
||||
SpanKind,
|
||||
TraceFlags,
|
||||
trace,
|
||||
} from '@opentelemetry/api';
|
||||
import { ComposableSampler, SamplingIntent } from './types';
|
||||
import { parseOtelTraceState } from './tracestate';
|
||||
import { INVALID_THRESHOLD, isValidThreshold, MIN_THRESHOLD } from './util';
|
||||
|
||||
class ComposableParentThresholdSampler implements ComposableSampler {
|
||||
private readonly description: string;
|
||||
|
||||
constructor(private readonly rootSampler: ComposableSampler) {
|
||||
this.description = `ComposableParentThresholdSampler(rootSampler=${rootSampler})`;
|
||||
}
|
||||
|
||||
getSamplingIntent(
|
||||
context: Context,
|
||||
traceId: string,
|
||||
spanName: string,
|
||||
spanKind: SpanKind,
|
||||
attributes: Attributes,
|
||||
links: Link[]
|
||||
): SamplingIntent {
|
||||
const parentSpanContext = trace.getSpanContext(context);
|
||||
if (!parentSpanContext || !isSpanContextValid(parentSpanContext)) {
|
||||
return this.rootSampler.getSamplingIntent(
|
||||
context,
|
||||
traceId,
|
||||
spanName,
|
||||
spanKind,
|
||||
attributes,
|
||||
links
|
||||
);
|
||||
}
|
||||
|
||||
const otTraceState = parseOtelTraceState(parentSpanContext.traceState);
|
||||
|
||||
if (isValidThreshold(otTraceState.threshold)) {
|
||||
return {
|
||||
threshold: otTraceState.threshold,
|
||||
thresholdReliable: true,
|
||||
};
|
||||
}
|
||||
|
||||
const threshold =
|
||||
parentSpanContext.traceFlags & TraceFlags.SAMPLED
|
||||
? MIN_THRESHOLD
|
||||
: INVALID_THRESHOLD;
|
||||
return {
|
||||
threshold,
|
||||
thresholdReliable: false,
|
||||
};
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.description;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a composable sampler that respects the sampling decision of the
|
||||
* parent span or falls back to the given sampler if it is a root span.
|
||||
*/
|
||||
export function createComposableParentThresholdSampler(
|
||||
rootSampler: ComposableSampler
|
||||
): ComposableSampler {
|
||||
return new ComposableParentThresholdSampler(rootSampler);
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import { ComposableSampler, SamplingIntent } from './types';
|
||||
import { INVALID_THRESHOLD, MAX_THRESHOLD } from './util';
|
||||
import { serializeTh } from './tracestate';
|
||||
|
||||
class ComposableTraceIDRatioBasedSampler implements ComposableSampler {
|
||||
private readonly intent: SamplingIntent;
|
||||
private readonly description: string;
|
||||
|
||||
constructor(ratio: number) {
|
||||
if (ratio < 0 || ratio > 1) {
|
||||
throw new Error(
|
||||
`Invalid sampling probability: ${ratio}. Must be between 0 and 1.`
|
||||
);
|
||||
}
|
||||
const threshold = calculateThreshold(ratio);
|
||||
const thresholdStr =
|
||||
threshold === MAX_THRESHOLD ? 'max' : serializeTh(threshold);
|
||||
if (threshold !== MAX_THRESHOLD) {
|
||||
this.intent = {
|
||||
threshold: threshold,
|
||||
thresholdReliable: true,
|
||||
};
|
||||
} else {
|
||||
// Same as AlwaysOff, notably the threshold is not considered reliable. The spec mentions
|
||||
// returning an instance of ComposableAlwaysOffSampler in this case but it seems clearer
|
||||
// if the description of the sampler matches the user's request.
|
||||
this.intent = {
|
||||
threshold: INVALID_THRESHOLD,
|
||||
thresholdReliable: false,
|
||||
};
|
||||
}
|
||||
this.description = `ComposableTraceIDRatioBasedSampler(threshold=${thresholdStr}, ratio=${ratio})`;
|
||||
}
|
||||
|
||||
getSamplingIntent(): SamplingIntent {
|
||||
return this.intent;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return this.description;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a composable sampler that samples each span with a fixed ratio.
|
||||
*/
|
||||
export function createComposableTraceIDRatioBasedSampler(
|
||||
ratio: number
|
||||
): ComposableSampler {
|
||||
return new ComposableTraceIDRatioBasedSampler(ratio);
|
||||
}
|
||||
|
||||
const probabilityThresholdScale = Math.pow(2, 56);
|
||||
|
||||
// TODO: Reduce threshold precision following spec recommendation of 4
|
||||
// to reduce size of serialized tracestate.
|
||||
function calculateThreshold(samplingProbability: number): bigint {
|
||||
return (
|
||||
MAX_THRESHOLD -
|
||||
BigInt(Math.round(samplingProbability * probabilityThresholdScale))
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import { TraceState } from '@opentelemetry/api';
|
||||
import {
|
||||
INVALID_RANDOM_VALUE,
|
||||
INVALID_THRESHOLD,
|
||||
isValidRandomValue,
|
||||
isValidThreshold,
|
||||
MAX_THRESHOLD,
|
||||
} from './util';
|
||||
|
||||
export type OtelTraceState = {
|
||||
/** The random value for sampling decisions in the trace. */
|
||||
randomValue: bigint;
|
||||
/** The upstream threshold for sampling decisions. */
|
||||
threshold: bigint;
|
||||
/** The rest of the "ot" tracestate value. */
|
||||
rest?: string[];
|
||||
};
|
||||
|
||||
export const INVALID_TRACE_STATE: OtelTraceState = Object.freeze({
|
||||
randomValue: INVALID_RANDOM_VALUE,
|
||||
threshold: INVALID_THRESHOLD,
|
||||
});
|
||||
|
||||
const TRACE_STATE_SIZE_LIMIT = 256;
|
||||
const MAX_VALUE_LENGTH = 14; // 56 bits, 4 bits per hex digit
|
||||
|
||||
export function parseOtelTraceState(
|
||||
traceState: TraceState | undefined
|
||||
): OtelTraceState {
|
||||
const ot = traceState?.get('ot');
|
||||
if (!ot || ot.length > TRACE_STATE_SIZE_LIMIT) {
|
||||
return INVALID_TRACE_STATE;
|
||||
}
|
||||
|
||||
let threshold = INVALID_THRESHOLD;
|
||||
let randomValue = INVALID_RANDOM_VALUE;
|
||||
|
||||
// Parse based on https://opentelemetry.io/docs/specs/otel/trace/tracestate-handling/
|
||||
const members = ot.split(';');
|
||||
let rest: string[] | undefined;
|
||||
for (const member of members) {
|
||||
if (member.startsWith('th:')) {
|
||||
threshold = parseTh(member.slice('th:'.length), INVALID_THRESHOLD);
|
||||
continue;
|
||||
}
|
||||
if (member.startsWith('rv:')) {
|
||||
randomValue = parseRv(member.slice('rv:'.length), INVALID_RANDOM_VALUE);
|
||||
continue;
|
||||
}
|
||||
if (!rest) {
|
||||
rest = [];
|
||||
}
|
||||
rest.push(member);
|
||||
}
|
||||
|
||||
return {
|
||||
randomValue,
|
||||
threshold,
|
||||
rest,
|
||||
};
|
||||
}
|
||||
|
||||
export function serializeTraceState(otTraceState: OtelTraceState): string {
|
||||
if (
|
||||
!isValidThreshold(otTraceState.threshold) &&
|
||||
!isValidRandomValue(otTraceState.randomValue) &&
|
||||
!otTraceState.rest
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const parts: string[] = [];
|
||||
if (
|
||||
isValidThreshold(otTraceState.threshold) &&
|
||||
otTraceState.threshold !== MAX_THRESHOLD
|
||||
) {
|
||||
parts.push(`th:${serializeTh(otTraceState.threshold)}`);
|
||||
}
|
||||
if (isValidRandomValue(otTraceState.randomValue)) {
|
||||
parts.push(`rv:${serializeRv(otTraceState.randomValue)}`);
|
||||
}
|
||||
if (otTraceState.rest) {
|
||||
parts.push(...otTraceState.rest);
|
||||
}
|
||||
let res = parts.join(';');
|
||||
while (res.length > TRACE_STATE_SIZE_LIMIT) {
|
||||
const lastSemicolon = res.lastIndexOf(';');
|
||||
if (lastSemicolon === -1) {
|
||||
break;
|
||||
}
|
||||
res = res.slice(0, lastSemicolon);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function parseTh(value: string, defaultValue: bigint): bigint {
|
||||
if (!value || value.length > MAX_VALUE_LENGTH) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return BigInt('0x' + value.padEnd(MAX_VALUE_LENGTH, '0'));
|
||||
} catch {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
function parseRv(value: string, defaultValue: bigint): bigint {
|
||||
if (!value || value.length !== MAX_VALUE_LENGTH) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
try {
|
||||
return BigInt(`0x${value}`);
|
||||
} catch {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
// hex value without trailing zeros
|
||||
export function serializeTh(threshold: bigint): string {
|
||||
if (threshold === 0n) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
const value = threshold.toString(16).padStart(MAX_VALUE_LENGTH, '0');
|
||||
let idxAfterNonZero = value.length;
|
||||
for (let i = value.length - 1; i >= 0; i--) {
|
||||
if (value[i] !== '0') {
|
||||
idxAfterNonZero = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Checked at beginning so there is definitely a nonzero.
|
||||
return value.slice(0, idxAfterNonZero);
|
||||
}
|
||||
|
||||
function serializeRv(randomValue: bigint): string {
|
||||
return randomValue.toString(16).padStart(MAX_VALUE_LENGTH, '0');
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import { Attributes, TraceState } from '@opentelemetry/api';
|
||||
import { type Sampler } from '@opentelemetry/sdk-trace-base';
|
||||
|
||||
/** Information to make a sampling decision. */
|
||||
export type SamplingIntent = {
|
||||
/** The sampling threshold value. A lower threshold increases the likelihood of sampling. */
|
||||
threshold: bigint;
|
||||
|
||||
/** Whether the threshold can be reliably used for Span-to-Metrics estimation. */
|
||||
thresholdReliable: boolean;
|
||||
|
||||
/** Any attributes to add to the span for the sampling result. */
|
||||
attributes?: Attributes;
|
||||
|
||||
/** How to update the TraceState for the span. */
|
||||
updateTraceState?: (ts: TraceState | undefined) => TraceState | undefined;
|
||||
};
|
||||
|
||||
/** A sampler that can be composed to make a final sampling decision. */
|
||||
export interface ComposableSampler {
|
||||
/** Returns the information to make a sampling decision. */
|
||||
getSamplingIntent(
|
||||
...args: Parameters<Sampler['shouldSample']>
|
||||
): SamplingIntent;
|
||||
|
||||
/** Returns the sampler name or short description with the configuration. */
|
||||
toString(): string;
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
export const INVALID_THRESHOLD = -1n;
|
||||
export const INVALID_RANDOM_VALUE = -1n;
|
||||
|
||||
const RANDOM_VALUE_BITS = 56n;
|
||||
export const MAX_THRESHOLD = 1n << RANDOM_VALUE_BITS; // 0% sampling
|
||||
export const MIN_THRESHOLD = 0n; // 100% sampling
|
||||
const MAX_RANDOM_VALUE = MAX_THRESHOLD - 1n;
|
||||
|
||||
export function isValidThreshold(threshold: bigint): boolean {
|
||||
return threshold >= MIN_THRESHOLD && threshold <= MAX_THRESHOLD;
|
||||
}
|
||||
|
||||
export function isValidRandomValue(randomValue: bigint): boolean {
|
||||
return randomValue >= 0n && randomValue <= MAX_RANDOM_VALUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
|
||||
import { context, SpanKind } from '@opentelemetry/api';
|
||||
import { SamplingDecision } from '@opentelemetry/sdk-trace-base';
|
||||
|
||||
import {
|
||||
createCompositeSampler,
|
||||
createComposableAlwaysOffSampler,
|
||||
} from '../src';
|
||||
import { traceIdGenerator } from './util';
|
||||
|
||||
describe('ComposableAlwaysOffSampler', () => {
|
||||
const composableSampler = createComposableAlwaysOffSampler();
|
||||
|
||||
it('should have a description', () => {
|
||||
assert.strictEqual(
|
||||
composableSampler.toString(),
|
||||
'ComposableAlwaysOffSampler'
|
||||
);
|
||||
});
|
||||
|
||||
it('should have a constant threshold', () => {
|
||||
assert.strictEqual(
|
||||
composableSampler.getSamplingIntent(
|
||||
context.active(),
|
||||
'unused',
|
||||
'span',
|
||||
SpanKind.SERVER,
|
||||
{},
|
||||
[]
|
||||
).threshold,
|
||||
-1n
|
||||
);
|
||||
});
|
||||
|
||||
it('should never sample', () => {
|
||||
const sampler = createCompositeSampler(composableSampler);
|
||||
const generator = traceIdGenerator();
|
||||
let numSampled = 0;
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
const result = sampler.shouldSample(
|
||||
context.active(),
|
||||
generator(),
|
||||
'span',
|
||||
SpanKind.SERVER,
|
||||
{},
|
||||
[]
|
||||
);
|
||||
if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) {
|
||||
numSampled++;
|
||||
}
|
||||
assert.strictEqual(result.traceState, undefined);
|
||||
}
|
||||
assert.strictEqual(numSampled, 0);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
|
||||
import { context, SpanKind } from '@opentelemetry/api';
|
||||
import { SamplingDecision } from '@opentelemetry/sdk-trace-base';
|
||||
|
||||
import {
|
||||
createCompositeSampler,
|
||||
createComposableAlwaysOnSampler,
|
||||
} from '../src';
|
||||
import { traceIdGenerator } from './util';
|
||||
|
||||
describe('ComposableAlwaysOnSampler', () => {
|
||||
const composableSampler = createComposableAlwaysOnSampler();
|
||||
|
||||
it('should have a description', () => {
|
||||
assert.strictEqual(
|
||||
composableSampler.toString(),
|
||||
'ComposableAlwaysOnSampler'
|
||||
);
|
||||
});
|
||||
|
||||
it('should have a constant threshold', () => {
|
||||
assert.strictEqual(
|
||||
composableSampler.getSamplingIntent(
|
||||
context.active(),
|
||||
'unused',
|
||||
'span',
|
||||
SpanKind.SERVER,
|
||||
{},
|
||||
[]
|
||||
).threshold,
|
||||
0n
|
||||
);
|
||||
});
|
||||
|
||||
it('should always sample', () => {
|
||||
const sampler = createCompositeSampler(composableSampler);
|
||||
const generator = traceIdGenerator();
|
||||
let numSampled = 0;
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
const result = sampler.shouldSample(
|
||||
context.active(),
|
||||
generator(),
|
||||
'span',
|
||||
SpanKind.SERVER,
|
||||
{},
|
||||
[]
|
||||
);
|
||||
if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) {
|
||||
numSampled++;
|
||||
}
|
||||
assert.strictEqual(result.traceState?.get('ot'), 'th:0');
|
||||
}
|
||||
assert.strictEqual(numSampled, 10000);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
|
||||
import {
|
||||
context,
|
||||
SpanContext,
|
||||
SpanKind,
|
||||
TraceFlags,
|
||||
trace,
|
||||
} from '@opentelemetry/api';
|
||||
import { SamplingDecision } from '@opentelemetry/sdk-trace-base';
|
||||
|
||||
import {
|
||||
createCompositeSampler,
|
||||
createComposableAlwaysOffSampler,
|
||||
createComposableAlwaysOnSampler,
|
||||
createComposableParentThresholdSampler,
|
||||
createComposableTraceIDRatioBasedSampler,
|
||||
} from '../src';
|
||||
import { INVALID_RANDOM_VALUE, INVALID_THRESHOLD } from '../src/util';
|
||||
import {
|
||||
INVALID_TRACE_STATE,
|
||||
parseOtelTraceState,
|
||||
serializeTraceState,
|
||||
} from '../src/tracestate';
|
||||
import { TraceState } from '@opentelemetry/core';
|
||||
|
||||
describe('ConsistentSampler', () => {
|
||||
const traceId = '00112233445566778800000000000000';
|
||||
const spanId = '0123456789abcdef';
|
||||
|
||||
[
|
||||
{
|
||||
sampler: createComposableAlwaysOnSampler(),
|
||||
parentSampled: true,
|
||||
parentThreshold: undefined,
|
||||
parentRandomValue: undefined,
|
||||
sampled: true,
|
||||
threshold: 0n,
|
||||
randomValue: INVALID_RANDOM_VALUE,
|
||||
testId: 'min threshold no parent random value',
|
||||
},
|
||||
{
|
||||
sampler: createComposableAlwaysOnSampler(),
|
||||
parentSampled: true,
|
||||
parentThreshold: undefined,
|
||||
parentRandomValue: 0x7f99aa40c02744n,
|
||||
sampled: true,
|
||||
threshold: 0n,
|
||||
randomValue: 0x7f99aa40c02744n,
|
||||
testId: 'min threshold with parent random value',
|
||||
},
|
||||
{
|
||||
sampler: createComposableAlwaysOffSampler(),
|
||||
parentSampled: true,
|
||||
parentThreshold: undefined,
|
||||
parentRandomValue: undefined,
|
||||
sampled: false,
|
||||
threshold: INVALID_THRESHOLD,
|
||||
randomValue: INVALID_RANDOM_VALUE,
|
||||
testId: 'max threshold',
|
||||
},
|
||||
{
|
||||
sampler: createComposableParentThresholdSampler(
|
||||
createComposableAlwaysOnSampler()
|
||||
),
|
||||
parentSampled: false,
|
||||
parentThreshold: 0x7f99aa40c02744n,
|
||||
parentRandomValue: 0x7f99aa40c02744n,
|
||||
sampled: true,
|
||||
threshold: 0x7f99aa40c02744n,
|
||||
randomValue: 0x7f99aa40c02744n,
|
||||
testId: 'parent based in consistent mode',
|
||||
},
|
||||
{
|
||||
sampler: createComposableParentThresholdSampler(
|
||||
createComposableAlwaysOnSampler()
|
||||
),
|
||||
parentSampled: true,
|
||||
parentThreshold: undefined,
|
||||
parentRandomValue: undefined,
|
||||
sampled: true,
|
||||
threshold: INVALID_THRESHOLD,
|
||||
randomValue: INVALID_RANDOM_VALUE,
|
||||
testId: 'parent based in legacy mode',
|
||||
},
|
||||
{
|
||||
sampler: createComposableTraceIDRatioBasedSampler(0.5),
|
||||
parentSampled: true,
|
||||
parentThreshold: undefined,
|
||||
parentRandomValue: 0x7fffffffffffffn,
|
||||
sampled: false,
|
||||
threshold: INVALID_THRESHOLD,
|
||||
randomValue: 0x7fffffffffffffn,
|
||||
testId: 'half threshold not sampled',
|
||||
},
|
||||
{
|
||||
sampler: createComposableTraceIDRatioBasedSampler(0.5),
|
||||
parentSampled: false,
|
||||
parentThreshold: undefined,
|
||||
parentRandomValue: 0x80000000000000n,
|
||||
sampled: true,
|
||||
threshold: 0x80000000000000n,
|
||||
randomValue: 0x80000000000000n,
|
||||
testId: 'half threshold sampled',
|
||||
},
|
||||
{
|
||||
sampler: createComposableTraceIDRatioBasedSampler(1.0),
|
||||
parentSampled: false,
|
||||
parentThreshold: 0x80000000000000n,
|
||||
parentRandomValue: 0x80000000000000n,
|
||||
sampled: true,
|
||||
threshold: 0n,
|
||||
randomValue: 0x80000000000000n,
|
||||
testId: 'parent inviolating invariant',
|
||||
},
|
||||
].forEach(
|
||||
({
|
||||
sampler,
|
||||
parentSampled,
|
||||
parentThreshold,
|
||||
parentRandomValue,
|
||||
sampled,
|
||||
threshold,
|
||||
randomValue,
|
||||
testId,
|
||||
}) => {
|
||||
it(`should sample with ${testId}`, () => {
|
||||
let parentOtTraceState = INVALID_TRACE_STATE;
|
||||
if (parentThreshold !== undefined) {
|
||||
parentOtTraceState = {
|
||||
...parentOtTraceState,
|
||||
threshold: parentThreshold,
|
||||
};
|
||||
}
|
||||
if (parentRandomValue !== undefined) {
|
||||
parentOtTraceState = {
|
||||
...parentOtTraceState,
|
||||
randomValue: parentRandomValue,
|
||||
};
|
||||
}
|
||||
const parentOt = serializeTraceState(parentOtTraceState);
|
||||
const parentTraceState = parentOt
|
||||
? new TraceState().set('ot', parentOt)
|
||||
: undefined;
|
||||
const traceFlags = parentSampled ? TraceFlags.SAMPLED : TraceFlags.NONE;
|
||||
const parentSpanContext: SpanContext = {
|
||||
traceId,
|
||||
spanId,
|
||||
traceFlags,
|
||||
traceState: parentTraceState,
|
||||
};
|
||||
const parentContext = trace.setSpanContext(
|
||||
context.active(),
|
||||
parentSpanContext
|
||||
);
|
||||
|
||||
const result = createCompositeSampler(sampler).shouldSample(
|
||||
parentContext,
|
||||
traceId,
|
||||
'name',
|
||||
SpanKind.INTERNAL,
|
||||
{},
|
||||
[]
|
||||
);
|
||||
const expectedDecision = sampled
|
||||
? SamplingDecision.RECORD_AND_SAMPLED
|
||||
: SamplingDecision.NOT_RECORD;
|
||||
const state = parseOtelTraceState(result.traceState);
|
||||
|
||||
assert.strictEqual(result.decision, expectedDecision);
|
||||
assert.strictEqual(state.threshold, threshold);
|
||||
assert.strictEqual(state.randomValue, randomValue);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
import * as assert from 'assert';
|
||||
|
||||
import { context, SpanKind } from '@opentelemetry/api';
|
||||
import { SamplingDecision } from '@opentelemetry/sdk-trace-base';
|
||||
|
||||
import {
|
||||
createCompositeSampler,
|
||||
createComposableTraceIDRatioBasedSampler,
|
||||
} from '../src';
|
||||
import { traceIdGenerator } from './util';
|
||||
import { parseOtelTraceState } from '../src/tracestate';
|
||||
import { INVALID_RANDOM_VALUE } from '../src/util';
|
||||
|
||||
describe('ComposableTraceIDRatioBasedSampler', () => {
|
||||
[
|
||||
{ ratio: 1.0, thresholdStr: '0' },
|
||||
{ ratio: 0.5, thresholdStr: '8' },
|
||||
{ ratio: 0.25, thresholdStr: 'c' },
|
||||
{ ratio: 1e-300, thresholdStr: 'max' },
|
||||
{ ratio: 0, thresholdStr: 'max' },
|
||||
].forEach(({ ratio, thresholdStr }) => {
|
||||
it(`should have a description for ratio ${ratio}`, () => {
|
||||
const sampler = createComposableTraceIDRatioBasedSampler(ratio);
|
||||
assert.strictEqual(
|
||||
sampler.toString(),
|
||||
`ComposableTraceIDRatioBasedSampler(threshold=${thresholdStr}, ratio=${ratio})`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
[
|
||||
{ ratio: 1.0, threshold: 0n },
|
||||
{ ratio: 0.5, threshold: 36028797018963968n },
|
||||
{ ratio: 0.25, threshold: 54043195528445952n },
|
||||
{ ratio: 0.125, threshold: 63050394783186944n },
|
||||
{ ratio: 0.0, threshold: 72057594037927936n },
|
||||
{ ratio: 0.45, threshold: 39631676720860364n },
|
||||
{ ratio: 0.2, threshold: 57646075230342348n },
|
||||
{ ratio: 0.13, threshold: 62690106812997304n },
|
||||
{ ratio: 0.05, threshold: 68454714336031539n },
|
||||
].forEach(({ ratio, threshold }) => {
|
||||
it(`should sample spans with ratio ${ratio}`, () => {
|
||||
const sampler = createCompositeSampler(
|
||||
createComposableTraceIDRatioBasedSampler(ratio)
|
||||
);
|
||||
|
||||
const generator = traceIdGenerator();
|
||||
let numSampled = 0;
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
const result = sampler.shouldSample(
|
||||
context.active(),
|
||||
generator(),
|
||||
'span',
|
||||
SpanKind.SERVER,
|
||||
{},
|
||||
[]
|
||||
);
|
||||
if (result.decision === SamplingDecision.RECORD_AND_SAMPLED) {
|
||||
numSampled++;
|
||||
const otTraceState = parseOtelTraceState(result.traceState);
|
||||
assert.strictEqual(otTraceState?.threshold, threshold);
|
||||
assert.strictEqual(otTraceState?.randomValue, INVALID_RANDOM_VALUE);
|
||||
}
|
||||
}
|
||||
const expectedNumSampled = 10000 * ratio;
|
||||
assert.ok(
|
||||
Math.abs(numSampled - expectedNumSampled) < 50,
|
||||
`expected ${expectedNumSampled}, have ${numSampled}`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { serializeTraceState, parseOtelTraceState } from '../src/tracestate';
|
||||
import { TraceState } from '@opentelemetry/core';
|
||||
|
||||
describe('OtelTraceState', () => {
|
||||
[
|
||||
{ input: 'a', output: 'a' },
|
||||
{ input: '#', output: '#' },
|
||||
{ input: 'rv:1234567890abcd', output: 'rv:1234567890abcd' },
|
||||
{ input: 'rv:01020304050607', output: 'rv:01020304050607' },
|
||||
{ input: 'rv:1234567890abcde', output: '' },
|
||||
{ input: 'th:1234567890abcd', output: 'th:1234567890abcd' },
|
||||
{ input: 'th:1234567890abcd', output: 'th:1234567890abcd' },
|
||||
{ input: 'th:10000000000000', output: 'th:1' },
|
||||
{ input: 'th:1234500000000', output: 'th:12345' },
|
||||
{ input: 'th:0', output: 'th:0' },
|
||||
{ input: 'th:100000000000000', output: '' },
|
||||
{ input: 'th:1234567890abcde', output: '' },
|
||||
{
|
||||
input: `a:${''.padEnd(214, 'X')};rv:1234567890abcd;th:1234567890abcd;x:3`,
|
||||
output: `th:1234567890abcd;rv:1234567890abcd;a:${''.padEnd(214, 'X')};x:3`,
|
||||
testId: 'long',
|
||||
},
|
||||
{ input: 'th:x', output: '' },
|
||||
{ input: 'th:100000000000000', output: '' },
|
||||
{ input: 'th:10000000000000', output: 'th:1' },
|
||||
{ input: 'th:1000000000000', output: 'th:1' },
|
||||
{ input: 'th:100000000000', output: 'th:1' },
|
||||
{ input: 'th:10000000000', output: 'th:1' },
|
||||
{ input: 'th:1000000000', output: 'th:1' },
|
||||
{ input: 'th:100000000', output: 'th:1' },
|
||||
{ input: 'th:10000000', output: 'th:1' },
|
||||
{ input: 'th:1000000', output: 'th:1' },
|
||||
{ input: 'th:100000', output: 'th:1' },
|
||||
{ input: 'th:10000', output: 'th:1' },
|
||||
{ input: 'th:1000', output: 'th:1' },
|
||||
{ input: 'th:100', output: 'th:1' },
|
||||
{ input: 'th:10', output: 'th:1' },
|
||||
{ input: 'th:1', output: 'th:1' },
|
||||
{ input: 'th:10000000000001', output: 'th:10000000000001' },
|
||||
{ input: 'th:10000000000010', output: 'th:1000000000001' },
|
||||
{ input: 'rv:x', output: '' },
|
||||
{ input: 'rv:100000000000000', output: '' },
|
||||
{ input: 'rv:10000000000000', output: 'rv:10000000000000' },
|
||||
{ input: 'rv:1000000000000', output: '' },
|
||||
].forEach(({ input, output, testId }) => {
|
||||
it(`should round trip ${testId || `from ${input} to ${output}`}`, () => {
|
||||
const result = serializeTraceState(
|
||||
parseOtelTraceState(new TraceState().set('ot', input))
|
||||
);
|
||||
assert.strictEqual(result, output);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
// Use a fixed seed simple but reasonable random number generator for consistent tests.
|
||||
// Unlike many languages, there isn't a way to set the seed of the built-in random.
|
||||
|
||||
function splitmix32(a: number) {
|
||||
return function () {
|
||||
a |= 0;
|
||||
a = (a + 0x9e3779b9) | 0;
|
||||
let t = a ^ (a >>> 16);
|
||||
t = Math.imul(t, 0x21f0aaad);
|
||||
t = t ^ (t >>> 15);
|
||||
t = Math.imul(t, 0x735a2d97);
|
||||
return ((t = t ^ (t >>> 15)) >>> 0) / 4294967296;
|
||||
};
|
||||
}
|
||||
|
||||
export function traceIdGenerator(): () => string {
|
||||
const seed = 0xdeadbeef;
|
||||
const random = splitmix32(seed);
|
||||
// Pre-mix the state.
|
||||
for (let i = 0; i < 15; i++) {
|
||||
random();
|
||||
}
|
||||
return () => {
|
||||
const parts: string[] = [];
|
||||
// 32-bit randoms, concatenate 4 of them
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const val = Math.round(random() * 0xffffffff);
|
||||
parts.push(val.toString(16).padStart(8, '0'));
|
||||
}
|
||||
return parts.join('');
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.esm.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"outDir": "build/esm",
|
||||
"rootDir": "src",
|
||||
"tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../api"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/opentelemetry-core"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/opentelemetry-sdk-trace-base"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.esnext.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"outDir": "build/esnext",
|
||||
"rootDir": "src",
|
||||
"tsBuildInfoFile": "build/esnext/tsconfig.esnext.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../api"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/opentelemetry-core"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/opentelemetry-sdk-trace-base"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"outDir": "build",
|
||||
"rootDir": "."
|
||||
},
|
||||
"files": [],
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"test/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../api"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/opentelemetry-core"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/opentelemetry-sdk-trace-base"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1449,6 +1449,257 @@
|
|||
"@opentelemetry/api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite": {
|
||||
"name": "@opentelemetry/sampler-composite",
|
||||
"version": "0.205.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/sdk-trace-base": "2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/node": "18.6.5",
|
||||
"lerna": "6.6.2",
|
||||
"mocha": "11.1.0",
|
||||
"nyc": "17.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/@opentelemetry/core": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz",
|
||||
"integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": ">=1.0.0 <1.10.0"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/@opentelemetry/resources": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz",
|
||||
"integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": ">=1.3.0 <1.10.0"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/@opentelemetry/sdk-trace-base": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz",
|
||||
"integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/resources": "2.0.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.19.0 || >=20.6.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": ">=1.3.0 <1.10.0"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/@types/node": {
|
||||
"version": "18.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz",
|
||||
"integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/diff": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
|
||||
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/jackspeak": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/cliui": "^8.0.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/mocha": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz",
|
||||
"integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-colors": "^4.1.3",
|
||||
"browser-stdout": "^1.3.1",
|
||||
"chokidar": "^3.5.3",
|
||||
"debug": "^4.3.5",
|
||||
"diff": "^5.2.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"find-up": "^5.0.0",
|
||||
"glob": "^10.4.5",
|
||||
"he": "^1.2.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"log-symbols": "^4.1.0",
|
||||
"minimatch": "^5.1.6",
|
||||
"ms": "^2.1.3",
|
||||
"serialize-javascript": "^6.0.2",
|
||||
"strip-json-comments": "^3.1.1",
|
||||
"supports-color": "^8.1.1",
|
||||
"workerpool": "^6.5.1",
|
||||
"yargs": "^17.7.2",
|
||||
"yargs-parser": "^21.1.1",
|
||||
"yargs-unparser": "^2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"_mocha": "bin/_mocha",
|
||||
"mocha": "bin/mocha.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/mocha/node_modules/minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/path-scurry": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/workerpool": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
|
||||
"integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"experimental/packages/sampler-composite/node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"experimental/packages/sampler-jaeger-remote": {
|
||||
"name": "@opentelemetry/sampler-jaeger-remote",
|
||||
"version": "0.205.0",
|
||||
|
|
@ -5963,6 +6214,10 @@
|
|||
"resolved": "packages/opentelemetry-resources",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@opentelemetry/sampler-composite": {
|
||||
"resolved": "experimental/packages/sampler-composite",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@opentelemetry/sampler-jaeger-remote": {
|
||||
"resolved": "experimental/packages/sampler-jaeger-remote",
|
||||
"link": true
|
||||
|
|
@ -31041,6 +31296,175 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@opentelemetry/sampler-composite": {
|
||||
"version": "file:experimental/packages/sampler-composite",
|
||||
"requires": {
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/sdk-trace-base": "2.0.1",
|
||||
"@types/mocha": "10.0.10",
|
||||
"@types/node": "18.6.5",
|
||||
"lerna": "6.6.2",
|
||||
"mocha": "11.1.0",
|
||||
"nyc": "17.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@opentelemetry/core": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.0.1.tgz",
|
||||
"integrity": "sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==",
|
||||
"requires": {
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
}
|
||||
},
|
||||
"@opentelemetry/resources": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.0.1.tgz",
|
||||
"integrity": "sha512-dZOB3R6zvBwDKnHDTB4X1xtMArB/d324VsbiPkX/Yu0Q8T2xceRthoIVFhJdvgVM2QhGVUyX9tzwiNxGtoBJUw==",
|
||||
"requires": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
}
|
||||
},
|
||||
"@opentelemetry/sdk-trace-base": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.0.1.tgz",
|
||||
"integrity": "sha512-xYLlvk/xdScGx1aEqvxLwf6sXQLXCjk3/1SQT9X9AoN5rXRhkdvIFShuNNmtTEPRBqcsMbS4p/gJLNI2wXaDuQ==",
|
||||
"requires": {
|
||||
"@opentelemetry/core": "2.0.1",
|
||||
"@opentelemetry/resources": "2.0.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.29.0"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "18.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz",
|
||||
"integrity": "sha512-Xjt5ZGUa5WusGZJ4WJPbOT8QOqp6nDynVFRKcUt32bOgvXEoc6o085WNkYTMO7ifAj2isEfQQ2cseE+wT6jsRw==",
|
||||
"dev": true
|
||||
},
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"diff": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
|
||||
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
|
||||
"dev": true
|
||||
},
|
||||
"glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
}
|
||||
},
|
||||
"jackspeak": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
|
||||
"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@isaacs/cliui": "^8.0.2",
|
||||
"@pkgjs/parseargs": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
|
||||
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "10.4.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mocha": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz",
|
||||
"integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-colors": "^4.1.3",
|
||||
"browser-stdout": "^1.3.1",
|
||||
"chokidar": "^3.5.3",
|
||||
"debug": "^4.3.5",
|
||||
"diff": "^5.2.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"find-up": "^5.0.0",
|
||||
"glob": "^10.4.5",
|
||||
"he": "^1.2.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"log-symbols": "^4.1.0",
|
||||
"minimatch": "^5.1.6",
|
||||
"ms": "^2.1.3",
|
||||
"serialize-javascript": "^6.0.2",
|
||||
"strip-json-comments": "^3.1.1",
|
||||
"supports-color": "^8.1.1",
|
||||
"workerpool": "^6.5.1",
|
||||
"yargs": "^17.7.2",
|
||||
"yargs-parser": "^21.1.1",
|
||||
"yargs-unparser": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"path-scurry": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
|
||||
"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^10.2.0",
|
||||
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"workerpool": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz",
|
||||
"integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@opentelemetry/sampler-jaeger-remote": {
|
||||
"version": "file:experimental/packages/sampler-jaeger-remote",
|
||||
"requires": {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@
|
|||
{
|
||||
"path": "experimental/packages/otlp-transformer/tsconfig.esm.json"
|
||||
},
|
||||
{
|
||||
"path": "experimental/packages/sampler-composite/tsconfig.esm.json"
|
||||
},
|
||||
{
|
||||
"path": "experimental/packages/sdk-logs/tsconfig.esm.json"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@
|
|||
{
|
||||
"path": "experimental/packages/otlp-transformer/tsconfig.esnext.json"
|
||||
},
|
||||
{
|
||||
"path": "experimental/packages/sampler-composite/tsconfig.esnext.json"
|
||||
},
|
||||
{
|
||||
"path": "experimental/packages/sdk-logs/tsconfig.esnext.json"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
"experimental/packages/otlp-exporter-base",
|
||||
"experimental/packages/otlp-grpc-exporter-base",
|
||||
"experimental/packages/otlp-transformer",
|
||||
"experimental/packages/sampler-composite",
|
||||
"experimental/packages/sampler-jaeger-remote",
|
||||
"experimental/packages/sdk-logs",
|
||||
"experimental/packages/shim-opencensus",
|
||||
|
|
@ -126,6 +127,9 @@
|
|||
{
|
||||
"path": "experimental/packages/otlp-transformer"
|
||||
},
|
||||
{
|
||||
"path": "experimental/packages/sampler-composite"
|
||||
},
|
||||
{
|
||||
"path": "experimental/packages/sampler-jaeger-remote"
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue