Skip to content

Commit

Permalink
Merge pull request #469 from solarwinds/NH-94218
Browse files Browse the repository at this point in the history
Add back lambda JSON sampling
  • Loading branch information
raphael-theriault-swi authored Oct 23, 2024
2 parents 68a0116 + 360052c commit b781d23
Show file tree
Hide file tree
Showing 20 changed files with 580 additions and 102 deletions.
9 changes: 9 additions & 0 deletions .yarn/versions/91299f24.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
releases:
"@solarwinds-apm/dependencies": patch
"@solarwinds-apm/sampling": major
"@solarwinds-apm/test": patch
solarwinds-apm: minor

declined:
- "@solarwinds-apm/bindings"
- "@solarwinds-apm/compat"
2 changes: 1 addition & 1 deletion packages/dependencies/src/node-modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

import { type Dirent, promises as fs } from "node:fs"
import { createRequire } from "node:module"
import * as path from "node:path"
import path from "node:path"

import { type Dependencies, type Package } from "./index.js"

Expand Down
4 changes: 2 additions & 2 deletions packages/dependencies/src/pnp-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import * as fs from "node:fs/promises"
import * as path from "node:path"
import fs from "node:fs/promises"
import path from "node:path"

import { type Dependencies, type Package } from "./index.js"

Expand Down
50 changes: 27 additions & 23 deletions packages/sampling/src/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,31 @@ limitations under the License.

import { metrics, ValueType } from "@opentelemetry/api"

const meter = metrics.getMeter("sw.apm.sampling.metrics")

export const counters = {
requestCount: meter.createCounter("trace.service.request_count", {
valueType: ValueType.INT,
}),
sampleCount: meter.createCounter("trace.service.samplecount", {
valueType: ValueType.INT,
}),
traceCount: meter.createCounter("trace.service.tracecount", {
valueType: ValueType.INT,
}),
throughTraceCount: meter.createCounter("trace.service.through_trace_count", {
valueType: ValueType.INT,
}),
triggeredTraceCount: meter.createCounter(
"trace.service.triggered_trace_count",
{ valueType: ValueType.INT },
),
tokenBucketExhaustionCount: meter.createCounter(
"trace.service.tokenbucket_exhaustion_count",
{ valueType: ValueType.INT },
),
export const counters = () => {
const meter = metrics.getMeter("sw.apm.sampling.metrics")
return {
requestCount: meter.createCounter("trace.service.request_count", {
valueType: ValueType.INT,
}),
sampleCount: meter.createCounter("trace.service.samplecount", {
valueType: ValueType.INT,
}),
traceCount: meter.createCounter("trace.service.tracecount", {
valueType: ValueType.INT,
}),
throughTraceCount: meter.createCounter(
"trace.service.through_trace_count",
{
valueType: ValueType.INT,
},
),
triggeredTraceCount: meter.createCounter(
"trace.service.triggered_trace_count",
{ valueType: ValueType.INT },
),
tokenBucketExhaustionCount: meter.createCounter(
"trace.service.tokenbucket_exhaustion_count",
{ valueType: ValueType.INT },
),
}
}
35 changes: 18 additions & 17 deletions packages/sampling/src/sampler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ interface SampleState {
* By extending this class neither needs to reimplement shared sampling logic.
*/
export abstract class OboeSampler implements Sampler {
readonly #counters = counters()
readonly #buckets: Record<BucketType, TokenBucket> = {
[BucketType.DEFAULT]: new TokenBucket({
interval: BUCKET_INTERVAL,
Expand All @@ -106,7 +107,6 @@ export abstract class OboeSampler implements Sampler {
}),
}
#settings: Settings | undefined = undefined
#updated: number = Date.now()

constructor(protected readonly logger: DiagLogger) {
for (const bucket of Object.values(this.#buckets)) {
Expand Down Expand Up @@ -142,6 +142,8 @@ export abstract class OboeSampler implements Sampler {
headers: this.requestHeaders(...params),
}

this.#counters.requestCount.add(1, {}, context)

if (s.headers["X-Trace-Options"]) {
s.traceOptions = {
...parseTraceOptions(s.headers["X-Trace-Options"], this.logger),
Expand Down Expand Up @@ -202,8 +204,6 @@ export abstract class OboeSampler implements Sampler {
return { decision: SamplingDecision.NOT_RECORD, attributes: s.attributes }
}

counters.requestCount.add(1, {}, context)

// https://swicloud.atlassian.net/wiki/spaces/NIT/pages/3815473156/Tracing+Decision+Tree
if (s.traceState && TRACESTATE_REGEXP.test(s.traceState)) {
this.logger.debug("context is valid for parent-based sampling")
Expand Down Expand Up @@ -248,8 +248,8 @@ export abstract class OboeSampler implements Sampler {
if (sampled) {
this.logger.debug("parent is sampled; record and sample")

counters.traceCount.add(1, {}, context)
counters.throughTraceCount.add(1, {}, context)
this.#counters.traceCount.add(1, {}, context)
this.#counters.throughTraceCount.add(1, {}, context)

s.decision = SamplingDecision.RECORD_AND_SAMPLED
} else {
Expand Down Expand Up @@ -293,8 +293,8 @@ export abstract class OboeSampler implements Sampler {
if (bucket.consume()) {
this.logger.debug("sufficient capacity; record and sample")

counters.triggeredTraceCount.add(1, {}, context)
counters.traceCount.add(1, {}, context)
this.#counters.triggeredTraceCount.add(1, {}, context)
this.#counters.traceCount.add(1, {}, context)

s.traceOptions!.response.triggerTrace = TriggerTrace.OK
s.decision = SamplingDecision.RECORD_AND_SAMPLED
Expand All @@ -320,7 +320,7 @@ export abstract class OboeSampler implements Sampler {
s.attributes[SAMPLE_RATE_ATTRIBUTE] = dice.rate
s.attributes[SAMPLE_SOURCE_ATTRIBUTE] = s.settings!.sampleSource

counters.sampleCount.add(1, {}, context)
this.#counters.sampleCount.add(1, {}, context)

if (dice.roll()) {
this.logger.debug("dice roll success; checking capacity")
Expand All @@ -332,13 +332,13 @@ export abstract class OboeSampler implements Sampler {
if (bucket.consume()) {
this.logger.debug("sufficient capacity; record and sample")

counters.traceCount.add(1, {}, context)
this.#counters.traceCount.add(1, {}, context)

s.decision = SamplingDecision.RECORD_AND_SAMPLED
} else {
this.logger.debug("insufficient capacity; record only")

counters.tokenBucketExhaustionCount.add(1, {}, context)
this.#counters.tokenBucketExhaustionCount.add(1, {}, context)

s.decision = SamplingDecision.RECORD
}
Expand Down Expand Up @@ -370,13 +370,14 @@ export abstract class OboeSampler implements Sampler {
protected updateSettings(settings: Settings): void {
this.logger.debug("settings updated", settings)

this.#settings = settings
this.#updated = Date.now()
if (settings.timestamp > (this.#settings?.timestamp ?? 0)) {
this.#settings = settings

for (const [type, bucket] of Object.entries(this.#buckets)) {
const settings = this.#settings.buckets[type as BucketType]
if (settings) {
bucket.update(settings)
for (const [type, bucket] of Object.entries(this.#buckets)) {
const settings = this.#settings.buckets[type as BucketType]
if (settings) {
bucket.update(settings)
}
}
}
}
Expand Down Expand Up @@ -428,7 +429,7 @@ export abstract class OboeSampler implements Sampler {
return
}

const expiry = this.#updated + this.#settings.ttl * 1000
const expiry = (this.#settings.timestamp + this.#settings.ttl) * 1000
if (Date.now() > expiry) {
this.logger.debug("settings expired, removing")
this.#settings = undefined
Expand Down
1 change: 1 addition & 0 deletions packages/sampling/src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface Settings {
flags: number
buckets: Partial<Record<BucketType, BucketSettings>>
signatureKey?: Uint8Array
timestamp: number
ttl: number
}

Expand Down
Loading

0 comments on commit b781d23

Please sign in to comment.