Skip to content

Commit

Permalink
feat(telemetry): Added sentry telemetry functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
sullivanpj committed Sep 13, 2024
1 parent 6ca1c8d commit a29cc50
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 498 deletions.
8 changes: 1 addition & 7 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@
"useFlatConfig": true
}
},
"@storm-software/workspace-tools/plugins/typescript",
{
"plugin": "@nx/rollup/plugin",
"options": {
"buildTargetName": "build"
}
}
"@storm-software/workspace-tools/plugins/typescript"
]
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@
"@nx/react": "19.7.3",
"@nx/react-native": "19.7.3",
"@nx/rollup": "19.7.3",
"@nx/rspack": "^19.7.1",
"@nx/workspace": "19.7.3",
"@storm-software/build-tools": "latest",
"@storm-software/config": "latest",
Expand Down
13 changes: 4 additions & 9 deletions packages/server-result/src/server-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ export type ServerResultMeta = {
/**
* The server endpoint/action name
*/
endpoint: string;
serviceId: string;
};

export type ServerResult<T> =
| {
| ({
/**
* The meta data returned by the server
*/
meta: ServerResultMeta;

} & {
/**
* The data returned by the server
*/
Expand All @@ -57,13 +57,8 @@ export type ServerResult<T> =
* The message returned by the server
*/
message?: MessageDetails;
}
})
| {
/**
* The meta data returned by the server
*/
meta: ServerResultMeta;

/**
* The errors returned by the server
*/
Expand Down
6 changes: 3 additions & 3 deletions packages/server-result/src/utilities/create-server-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { ServerResult, ServerResultMeta } from "../server-result";
export interface CreateServerResultMetaOptions {
correlationId?: string;
userId: string;
endpoint: string;
serviceId: string;
}

export interface CreateServerResultOptions<T> {
Expand All @@ -40,13 +40,13 @@ export interface CreateServerResultOptions<T> {
export const createServerResultMeta = ({
correlationId,
userId,
endpoint
serviceId
}: CreateServerResultMetaOptions): ServerResultMeta => {
return {
correlationId: correlationId || uuid(),
timestamp: StormDateTime.current(),
userId,
endpoint
serviceId
};
};

Expand Down
5 changes: 5 additions & 0 deletions packages/telemetry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,20 @@
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/auto-instrumentations-node": "^0.50.0",
"@opentelemetry/context-async-hooks": "^1.26.0",
"@opentelemetry/exporter-metrics-otlp-proto": "^0.53.0",
"@opentelemetry/exporter-prometheus": "^0.53.0",
"@opentelemetry/exporter-trace-otlp-proto": "^0.53.0",
"@opentelemetry/instrumentation-pino": "^0.42.0",
"@opentelemetry/resources": "^1.26.0",
"@opentelemetry/sdk-metrics": "^1.26.0",
"@opentelemetry/sdk-node": "^0.53.0",
"@opentelemetry/sdk-trace-base": "^1.26.0",
"@opentelemetry/sdk-trace-node": "^1.26.0",
"@opentelemetry/semantic-conventions": "^1.27.0",
"@sentry/node": "^8.30.0",
"@sentry/opentelemetry": "^8.30.0",
"@sentry/types": "^8.30.0",
"@storm-software/config": "latest",
"@storm-software/config-tools": "latest",
"pino": "8.16.2",
Expand Down
4 changes: 2 additions & 2 deletions packages/telemetry/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

import { ErrorCode } from "@storm-stack/errors/errors";

export type TelemetryErrorCode = ErrorCode | "missing_service_id";
export type TelemetryErrorCode = ErrorCode | "missing_service_name";
export const TelemetryErrorCode = {
...ErrorCode,
missing_service_id: "missing_service_id" as TelemetryErrorCode
missing_service_name: "missing_service_name" as TelemetryErrorCode
};
16 changes: 10 additions & 6 deletions packages/telemetry/src/otel/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ import {
ATTR_SERVICE_VERSION
} from "@opentelemetry/semantic-conventions";

export interface LoadOtelOptions {
serviceId: string;
export interface InitOtelOptions {
serviceName: string;
serviceVersion?: string;
}

export const initOtel = (options: LoadOtelOptions) => {
export const initOtel = (options: InitOtelOptions) => {
const sdk = new NodeSDK({
resource: new Resource({
[ATTR_SERVICE_NAME]: options.serviceId,
[ATTR_SERVICE_VERSION]: options.serviceVersion || "1.0"
[ATTR_SERVICE_NAME]: options.serviceName,
[ATTR_SERVICE_VERSION]: options.serviceVersion || "1.0.0"
}),
spanProcessor: new tracing.SimpleSpanProcessor(
new tracing.ConsoleSpanExporter()
Expand All @@ -51,7 +51,11 @@ export const initOtel = (options: LoadOtelOptions) => {
instrumentations: [
getNodeAutoInstrumentations(),
new PinoInstrumentation({
// See below for Pino instrumentation options.
logKeys: {
traceId: "correlationId",
spanId: "spanId",
traceFlags: "data"
}
})
]
});
Expand Down
18 changes: 18 additions & 0 deletions packages/telemetry/src/sentry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*-------------------------------------------------------------------
⚡ Storm Software - Storm Stack
This code was released as part of the Storm Stack project. Storm Stack
is maintained by Storm Software under the Apache-2.0 License, and is
free for commercial and private use. For more information, please visit
our licensing page.
Website: https://stormsoftware.com
Repository: https://github.com/storm-software/storm-stack
Documentation: https://stormsoftware.com/projects/storm-stack/docs
Contact: https://stormsoftware.com/contact
License: https://stormsoftware.com/projects/storm-stack/license
-------------------------------------------------------------------*/

export * from "./init";
71 changes: 71 additions & 0 deletions packages/telemetry/src/sentry/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*-------------------------------------------------------------------
⚡ Storm Software - Storm Stack
This code was released as part of the Storm Stack project. Storm Stack
is maintained by Storm Software under the Apache-2.0 License, and is
free for commercial and private use. For more information, please visit
our licensing page.
Website: https://stormsoftware.com
Repository: https://github.com/storm-software/storm-stack
Documentation: https://stormsoftware.com/projects/storm-stack/docs
Contact: https://stormsoftware.com/contact
License: https://stormsoftware.com/projects/storm-stack/license
-------------------------------------------------------------------*/

import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
import * as Sentry from "@sentry/node";
import {
SentryPropagator,
SentrySampler,
SentrySpanProcessor,
setOpenTelemetryContextAsyncContextStrategy,
setupEventContextTrace,
wrapContextManagerClass
} from "@sentry/opentelemetry";

export interface InitSentryOptions {
dsn: string;
serviceName: string;
serviceVersion?: string;
tracesSampleRate?: number;
}

export const initSentry = (options: InitSentryOptions) => {
Sentry.init({
dsn: options.dsn,
serverName: options.serviceName,
release: options.serviceVersion || "1.0.0",
environment: process.env.NODE_ENV,
skipOpenTelemetrySetup: true,
enabled: true,
enableTracing: true,
attachStacktrace: true,
sendClientReports: true,
parentSpanIsAlwaysRootSpan: false,
tracesSampleRate: options.tracesSampleRate ?? 0.8
});

const client = Sentry.getClient();
setupEventContextTrace(client);

const provider = new BasicTracerProvider({
sampler: new SentrySampler(client)
});

const SentryContextManager = wrapContextManagerClass(
AsyncLocalStorageContextManager
);

provider.addSpanProcessor(new SentrySpanProcessor());
provider.register({
propagator: new SentryPropagator(),
contextManager: new SentryContextManager()
});

setOpenTelemetryContextAsyncContextStrategy();
Sentry.validateOpenTelemetrySetup();
};
55 changes: 34 additions & 21 deletions packages/telemetry/src/storm-trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
-------------------------------------------------------------------*/

import { Context, Span, SpanOptions } from "@opentelemetry/api";
import { Context, Span, SpanKind, SpanOptions } from "@opentelemetry/api";
import { api } from "@opentelemetry/sdk-node";
import type { StormConfig } from "@storm-software/config";
import { StormError } from "@storm-stack/errors/storm-error";
import { StormLog } from "@storm-stack/logging/storm-log";
import { uuid } from "@storm-stack/unique-identifier/uuid";
import type pino from "pino";
import { TelemetryErrorCode } from "./errors";
import { initOtel } from "./otel/init";
import { initSentry } from "./sentry/init";
import type { TelemetryConfig } from "./types";

/**
Expand All @@ -38,32 +40,39 @@ export class StormTrace extends StormLog {
* Initialize the logger.
*
* @param config - The Storm config
* @param name - The name of the project to initialized the loggers for
* @param name - The name of the service to initialized the loggers for
* @returns The initialized loggers
*/
public static override initialize = (
config: StormConfig<"telemetry", TelemetryConfig>,
name?: string,
streams: (pino.DestinationStream | pino.StreamEntry<pino.Level>)[] = []
) => {
if (!name && !config.extensions.telemetry?.serviceId) {
throw StormError.create(TelemetryErrorCode.missing_service_id);
if (!name && !config.extensions.telemetry?.serviceName) {
throw StormError.create(TelemetryErrorCode.missing_service_name);
}

const serviceName = name || config.extensions.telemetry?.serviceName;

initOtel({
serviceId: name || config.extensions.telemetry?.serviceId
serviceName,
serviceVersion: config.extensions.telemetry?.serviceVersion
});
StormTrace.#tracer = api.trace.getTracer(
name || config.extensions.telemetry?.serviceId
);
initSentry({
dsn: "",
serviceName,
serviceVersion: config.extensions.telemetry?.serviceVersion
});

StormTrace.#tracer = api.trace.getTracer(serviceName);

StormLog.initialize(config, name, streams);
StormLog.initialize(config, serviceName, streams);
};

public static async span<TFunct extends (span: Span) => unknown>(
spanName: string,
spanId: string,
funct: TFunct,
options?: SpanOptions,
options: SpanOptions = {},
context?: Context
): Promise<ReturnType<TFunct>> {
const spanFunct = async (span: api.Span) => {
Expand All @@ -72,23 +81,27 @@ export class StormTrace extends StormLog {
return result as ReturnType<TFunct>;
};

if (options && context) {
const opts: SpanOptions = {
kind: SpanKind.SERVER,
attributes: {
...options?.attributes,
correlationId: uuid(),
serviceName: StormTrace.name
},
...options
};
if (context) {
return StormTrace.#tracer.startActiveSpan(
`${StormTrace.name} > ${spanName}`,
options,
`${StormTrace.name} > ${spanId}`,
opts,
context,
spanFunct
);
} else if (options) {
return StormTrace.#tracer.startActiveSpan(
`${StormTrace.name} > ${spanName}`,
options,
spanFunct
);
}

return StormTrace.#tracer.startActiveSpan(
`${StormTrace.name} > ${spanName}`,
`${StormTrace.name} > ${spanId}`,
opts,
spanFunct
);
}
Expand Down
Loading

0 comments on commit a29cc50

Please sign in to comment.