Skip to content

Commit

Permalink
Merge pull request #162 from solarwinds/NH-61324
Browse files Browse the repository at this point in the history
Initial integration with `OboeAPI`
  • Loading branch information
raphael-theriault-swi authored Nov 17, 2023
2 parents f431771 + 79f6f75 commit 19134a8
Show file tree
Hide file tree
Showing 17 changed files with 309 additions and 119 deletions.
9 changes: 9 additions & 0 deletions .yarn/versions/450733cf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
releases:
"@solarwinds-apm/bindings": minor
"@solarwinds-apm/module": minor
"@solarwinds-apm/sdk": minor
solarwinds-apm: minor

declined:
- "@solarwinds-apm/dependencies"
- "@solarwinds-apm/test"
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@solarwinds-apm/solarwinds-apm",
"private": true,
"license": "Apache-2.0",
"packageManager": "[email protected].1",
"packageManager": "[email protected].2",
"workspaces": [
"examples",
"examples/*",
Expand Down
6 changes: 3 additions & 3 deletions packages/bindings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

const { IS_SERVERLESS } = require("@solarwinds-apm/module")

function triple() {
const platform = process.platform
const arch = process.arch
Expand All @@ -29,9 +31,7 @@ function triple() {
}

function serverless() {
const isServerless = "AWS_LAMBDA_FUNCTION_NAME" in process.env

if (isServerless) {
if (IS_SERVERLESS) {
return "-serverless"
} else {
return ""
Expand Down
19 changes: 11 additions & 8 deletions packages/bindings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@
"test": "swtest",
"oboe": "node oboe.js"
},
"dependencies": {
"@solarwinds-apm/module": "workspace:^"
},
"optionalDependencies": {
"@solarwinds-apm/bindings-linux-arm64-gnu": "workspace:*",
"@solarwinds-apm/bindings-linux-arm64-gnu-serverless": "workspace:*",
"@solarwinds-apm/bindings-linux-arm64-musl": "workspace:*",
"@solarwinds-apm/bindings-linux-x64-gnu": "workspace:*",
"@solarwinds-apm/bindings-linux-x64-gnu-serverless": "workspace:*",
"@solarwinds-apm/bindings-linux-x64-musl": "workspace:*"
},
"devDependencies": {
"@solarwinds-apm/eslint-config": "workspace:^",
"@solarwinds-apm/test": "workspace:^",
Expand All @@ -47,14 +58,6 @@
"typescript": "^5.2.2",
"zig-build": "^0.3.0"
},
"optionalDependencies": {
"@solarwinds-apm/bindings-linux-arm64-gnu": "workspace:*",
"@solarwinds-apm/bindings-linux-arm64-gnu-serverless": "workspace:*",
"@solarwinds-apm/bindings-linux-arm64-musl": "workspace:*",
"@solarwinds-apm/bindings-linux-x64-gnu": "workspace:*",
"@solarwinds-apm/bindings-linux-x64-gnu-serverless": "workspace:*",
"@solarwinds-apm/bindings-linux-x64-musl": "workspace:*"
},
"engines": {
"node": ">=16.13.0"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/module/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# @solarwinds-apm/module

Utilities for dealing with differences between CommonJS and ES Modules.
Utilities for obtaining information about the current module.
6 changes: 6 additions & 0 deletions packages/module/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { env } from "node:process"

/**
* Finds the current call site. Useful to replace `import.meta.url` or `__dirname`,
* or to get more than just a file name.
Expand All @@ -35,3 +37,7 @@ export function callsite(): NodeJS.CallSite {
Error.prepareStackTrace = prepareStackTrace
}
}

export const IS_AWS_LAMBDA = "AWS_LAMBDA_FUNCTION_NAME" in env

export const IS_SERVERLESS = IS_AWS_LAMBDA
10 changes: 8 additions & 2 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
},
"type": "commonjs",
"exports": {
".": "./dist/index.js"
".": "./dist/index.js",
"./otlp-exporter": "./dist/otlp-exporter.js"
},
"main": "./dist/index.js",
"files": [
Expand All @@ -41,14 +42,19 @@
"@solarwinds-apm/dependencies": "workspace:^",
"@solarwinds-apm/histogram": "workspace:^",
"@solarwinds-apm/lazy": "workspace:^",
"@solarwinds-apm/module": "workspace:^",
"semver": "^7.5.4"
},
"peerDependencies": {
"@opentelemetry/api": "^1.3.0"
"@opentelemetry/api": "^1.3.0",
"@opentelemetry/exporter-trace-otlp-grpc": ">=0.34.0"
},
"peerDependenciesMeta": {
"@opentelemetry/api": {
"optional": false
},
"@opentelemetry/exporter-trace-otlp-grpc": {
"optional": true
}
},
"devDependencies": {
Expand Down
44 changes: 44 additions & 0 deletions packages/sdk/src/metrics/serverless.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2023 SolarWinds Worldwide, LLC.
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.
*/

import { metrics } from "@opentelemetry/api"
import { type oboe } from "@solarwinds-apm/bindings"
import { lazy } from "@solarwinds-apm/lazy"

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

const counters = {
RequestCount: lazy(() => meter.createCounter("trace.service.request_count")),
TokenBucketExhaustionCount: lazy(() =>
meter.createCounter("trace.service.tokenbucket_exhaustion_count"),
),
TraceCount: lazy(() => meter.createCounter("trace.service.tracecount")),
SampleCount: lazy(() => meter.createCounter("trace.service.samplecount")),
ThroughTraceCount: lazy(() =>
meter.createCounter("trace.service.through_trace_count"),
),
TriggeredTraceCount: lazy(() =>
meter.createCounter("trace.service.triggered_trace_count"),
),
}

export function recordServerlessMetrics(serverlessApi: oboe.OboeAPI) {
for (const [name, counter] of Object.entries(counters)) {
const method = `consume${name}` as const
const value = serverlessApi[method]()
if (value !== false) counter.add(value)
}
}
41 changes: 41 additions & 0 deletions packages/sdk/src/otlp-exporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
Copyright 2023 SolarWinds Worldwide, LLC.
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.
*/

import { type ExportResult } from "@opentelemetry/core"
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc"
import { type ReadableSpan } from "@opentelemetry/sdk-trace-base"

import { cache } from "./cache"

export class SwOtlpExporter extends OTLPTraceExporter {
override export(
spans: ReadableSpan[],
resultCallback: (result: ExportResult) => void,
): void {
for (const span of spans) {
const context = span.spanContext()

const txname = cache.get(context)?.txname
if (txname) {
span.attributes["sw.transaction"] = txname
}

cache.clear(context)
}

super.export(spans, resultCallback)
}
}
5 changes: 2 additions & 3 deletions packages/sdk/src/patches/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { env } from "node:process"

import { type InstrumentationConfig } from "@opentelemetry/instrumentation"
import { IS_AWS_LAMBDA } from "@solarwinds-apm/module"

import { type Patch } from "."

export const patch: Patch<InstrumentationConfig> = (config) => ({
enabled: config.enabled ?? "AWS_LAMBDA_FUNCTION_NAME" in env,
enabled: config.enabled ?? IS_AWS_LAMBDA,
})
26 changes: 24 additions & 2 deletions packages/sdk/src/sampler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
TRACESTATE_TRACE_OPTIONS_RESPONSE_KEY,
} from "./context"
import { OboeError } from "./error"
import { recordServerlessMetrics } from "./metrics/serverless"

const ATTRIBUTES_SW_KEYS_KEY = "SWKeys"
const ATTRIBUTES_TRACESTATE_CAPTURE_KEY = "sw.w3c.tracestate"
Expand All @@ -57,10 +58,29 @@ const TRACE_OPTIONS_RESPONSE_TRIGGER_IGNORED = "ignored"
const TRACE_OPTIONS_RESPONSE_TRIGGER_NOT_REQUESTED = "not-requested"

export class SwSampler implements Sampler {
private readonly oboeDecisionFunction: (
options: oboe.DecisionOptions,
) => oboe.DecisionResult
private readonly recordMetricsFunction: () => void

constructor(
private readonly config: SwConfiguration,
private readonly logger: DiagLogger,
) {}
serverlessApi: oboe.OboeAPI | undefined,
) {
if (serverlessApi) {
this.oboeDecisionFunction =
serverlessApi.getTracingDecision.bind(serverlessApi)
this.recordMetricsFunction = () => {
recordServerlessMetrics(serverlessApi)
}
} else {
this.oboeDecisionFunction = oboe.Context.getDecisions
this.recordMetricsFunction = () => {
// noop
}
}
}

shouldSample(
parentContext: Context,
Expand Down Expand Up @@ -116,6 +136,8 @@ export class SwSampler implements Sampler {
traceOptions,
traceState,
)

this.recordMetricsFunction()
return { decision, traceState, attributes: newAttributes }
}

Expand All @@ -140,7 +162,7 @@ export class SwSampler implements Sampler {
traceparent = traceParent(parentSpanContext)
}

return oboe.Context.getDecisions({
return this.oboeDecisionFunction({
in_xtrace: traceparent,
custom_sample_rate: oboe.SETTINGS_UNSET,
custom_tracing_mode: tracingMode,
Expand Down
1 change: 1 addition & 0 deletions packages/solarwinds-apm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@opentelemetry/instrumentation": "~0.45.1",
"@opentelemetry/resources": "~1.18.1",
"@opentelemetry/sdk-metrics": "~1.18.1",
"@opentelemetry/sdk-trace-base": "~1.18.1",
"@opentelemetry/sdk-trace-node": "~1.18.1",
"@opentelemetry/semantic-conventions": "~1.18.1",
"@solarwinds-apm/bindings": "workspace:^",
Expand Down
Loading

0 comments on commit 19134a8

Please sign in to comment.