@ogcio/o11y-sdk-node 0.11.2 → 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/sdk-core/lib/utils/data-structures.js +1 -0
  2. package/dist/sdk-core/lib/utils/geo-context.d.ts +28 -0
  3. package/dist/sdk-core/lib/utils/geo-context.js +52 -0
  4. package/dist/sdk-core/lib/utils/geohash.d.ts +11 -0
  5. package/dist/sdk-core/lib/utils/geohash.js +52 -0
  6. package/dist/sdk-core/lib/utils/index.d.ts +3 -0
  7. package/dist/sdk-core/lib/utils/index.js +2 -0
  8. package/dist/sdk-node/index.d.ts +2 -1
  9. package/dist/sdk-node/index.js +1 -0
  10. package/dist/sdk-node/lib/geo/geo-baggage-propagator.d.ts +6 -0
  11. package/dist/sdk-node/lib/geo/geo-baggage-propagator.js +62 -0
  12. package/dist/sdk-node/lib/geo/index.d.ts +5 -0
  13. package/dist/sdk-node/lib/geo/index.js +4 -0
  14. package/dist/sdk-node/lib/index.d.ts +17 -5
  15. package/dist/sdk-node/lib/index.js +2 -1
  16. package/dist/sdk-node/lib/instrumentation.node.js +10 -1
  17. package/dist/sdk-node/lib/internals/redaction/redactors/index.d.ts +0 -12
  18. package/dist/sdk-node/lib/internals/redaction/redactors/index.js +4 -11
  19. package/dist/sdk-node/lib/metrics.js +27 -1
  20. package/dist/sdk-node/lib/presets/sentry-node.d.ts +1 -1
  21. package/dist/sdk-node/lib/processor/geo-enrich-log-processor.d.ts +7 -0
  22. package/dist/sdk-node/lib/processor/geo-enrich-log-processor.js +18 -0
  23. package/dist/sdk-node/lib/processor/geo-enrich-span-processor.d.ts +8 -0
  24. package/dist/sdk-node/lib/processor/geo-enrich-span-processor.js +18 -0
  25. package/dist/sdk-node/lib/processor/nextjs-logger-processor.d.ts +2 -2
  26. package/dist/sdk-node/lib/processor/nextjs-span-processor.d.ts +1 -1
  27. package/dist/sdk-node/lib/processor/on-ending-hook-span-processor.d.ts +2 -2
  28. package/dist/sdk-node/lib/url-sampler.js +1 -0
  29. package/dist/sdk-node/package.json +1 -1
  30. package/package.json +1 -1
  31. package/dist/sdk-node/lib/internals/redaction/redactors/email.d.ts +0 -8
  32. package/dist/sdk-node/lib/internals/redaction/redactors/email.js +0 -19
  33. package/dist/sdk-node/lib/internals/redaction/redactors/ip.d.ts +0 -8
  34. package/dist/sdk-node/lib/internals/redaction/redactors/ip.js +0 -20
  35. package/dist/sdk-node/lib/internals/redaction/redactors/ppsn.d.ts +0 -8
  36. package/dist/sdk-node/lib/internals/redaction/redactors/ppsn.js +0 -18
@@ -1,4 +1,5 @@
1
1
  import { _containsEncodedComponents } from "./string-decoding.js";
2
+ import { BasicRedactor } from "../redaction/index.js";
2
3
  const decoder = new TextDecoder();
3
4
  const encoder = new TextEncoder();
4
5
  /**
@@ -0,0 +1,28 @@
1
+ import type { Context } from "@opentelemetry/api";
2
+ export declare const geoBaggageKeys: readonly ["geo.country", "geo.city", "geo.hash"];
3
+ type GeoKey = (typeof geoBaggageKeys)[number];
4
+ export type GeoAttributes = Partial<Record<GeoKey, string>>;
5
+ export type GeoInput = {
6
+ lat?: number;
7
+ lon?: number;
8
+ country?: string;
9
+ city?: string;
10
+ };
11
+ /**
12
+ * Returns geo attributes from the given OTel context's baggage.
13
+ * Use this in span and log processors where the context is passed explicitly.
14
+ */
15
+ export declare function getGeoAttributesFromContext(ctx: Context): GeoAttributes;
16
+ /**
17
+ * Returns geo attributes for the current request context.
18
+ * Reads from OTel Baggage on the active context, set by GeoBaggagePropagator.
19
+ * Use this to manually enrich custom spans, logs, or metrics when geo-enrichment is enabled.
20
+ */
21
+ export declare function getGeoAttributes(): GeoAttributes;
22
+ /**
23
+ * Builds geo attributes from any combination of geo inputs.
24
+ * A geohash is computed automatically when both `lat` and `lon` are provided.
25
+ * Use this to create geo attributes to attach to signals when auto-enrichment is not enabled.
26
+ */
27
+ export declare function createGeoAttributesFrom(input: GeoInput): GeoAttributes;
28
+ export {};
@@ -0,0 +1,52 @@
1
+ import { context, propagation } from "@opentelemetry/api";
2
+ import { encodeGeohash } from "./geohash.js";
3
+ export const geoBaggageKeys = ["geo.country", "geo.city", "geo.hash"];
4
+ function fromBaggage(baggage) {
5
+ if (!baggage)
6
+ return {};
7
+ const attrs = {};
8
+ for (const key of geoBaggageKeys) {
9
+ const value = baggage.getEntry(key)?.value;
10
+ if (value)
11
+ attrs[key] = value;
12
+ }
13
+ return attrs;
14
+ }
15
+ /**
16
+ * Returns geo attributes from the given OTel context's baggage.
17
+ * Use this in span and log processors where the context is passed explicitly.
18
+ */
19
+ export function getGeoAttributesFromContext(ctx) {
20
+ return fromBaggage(propagation.getBaggage(ctx));
21
+ }
22
+ /**
23
+ * Returns geo attributes for the current request context.
24
+ * Reads from OTel Baggage on the active context, set by GeoBaggagePropagator.
25
+ * Use this to manually enrich custom spans, logs, or metrics when geo-enrichment is enabled.
26
+ */
27
+ export function getGeoAttributes() {
28
+ return fromBaggage(propagation.getBaggage(context.active()));
29
+ }
30
+ /**
31
+ * Builds geo attributes from any combination of geo inputs.
32
+ * A geohash is computed automatically when both `lat` and `lon` are provided.
33
+ * Use this to create geo attributes to attach to signals when auto-enrichment is not enabled.
34
+ */
35
+ export function createGeoAttributesFrom(input) {
36
+ const attrs = {};
37
+ if (input.country)
38
+ attrs["geo.country"] = input.country;
39
+ if (input.city)
40
+ attrs["geo.city"] = input.city;
41
+ if (input.lat !== undefined &&
42
+ input.lon !== undefined &&
43
+ input.lat >= -90 &&
44
+ input.lat <= 90 &&
45
+ input.lon >= -180 &&
46
+ input.lon <= 180) {
47
+ const hash = encodeGeohash(input.lat, input.lon, 4);
48
+ if (hash)
49
+ attrs["geo.hash"] = hash;
50
+ }
51
+ return attrs;
52
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Encode latitude and longitude into a geohash string.
3
+ * Alternates between longitude and latitude bits, bisects the coordinate range, accumulates 5 bits into an index into the BASE32 lookup table, and repeats until the desired precision is reached.
4
+ * See https://en.wikipedia.org/wiki/Geohash for algorithm details.
5
+ *
6
+ * @param lat Latitude (-90 to 90)
7
+ * @param lon Longitude (-180 to 180)
8
+ * @param precision Number of characters in the geohash (default: 4)
9
+ * @returns Geohash string of the given precision, or undefined if inputs are invalid
10
+ */
11
+ export declare function encodeGeohash(lat: number, lon: number, precision?: number): string | undefined;
@@ -0,0 +1,52 @@
1
+ const BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";
2
+ /**
3
+ * Encode latitude and longitude into a geohash string.
4
+ * Alternates between longitude and latitude bits, bisects the coordinate range, accumulates 5 bits into an index into the BASE32 lookup table, and repeats until the desired precision is reached.
5
+ * See https://en.wikipedia.org/wiki/Geohash for algorithm details.
6
+ *
7
+ * @param lat Latitude (-90 to 90)
8
+ * @param lon Longitude (-180 to 180)
9
+ * @param precision Number of characters in the geohash (default: 4)
10
+ * @returns Geohash string of the given precision, or undefined if inputs are invalid
11
+ */
12
+ export function encodeGeohash(lat, lon, precision = 4) {
13
+ if (!Number.isFinite(lat) || !Number.isFinite(lon))
14
+ return undefined;
15
+ if (!Number.isInteger(precision) || precision < 1 || precision > 8)
16
+ return undefined;
17
+ if (lat < -90 || lat > 90 || lon < -180 || lon > 180)
18
+ return undefined;
19
+ let latMin = -90;
20
+ let latMax = 90;
21
+ let lonMin = -180;
22
+ let lonMax = 180;
23
+ let hash = "";
24
+ let bit = 0;
25
+ let ch = 0;
26
+ let isLon = true;
27
+ while (hash.length < precision) {
28
+ const mid = isLon ? (lonMin + lonMax) / 2 : (latMin + latMax) / 2;
29
+ const value = isLon ? lon : lat;
30
+ if (value >= mid) {
31
+ ch |= 1 << (4 - bit);
32
+ if (isLon)
33
+ lonMin = mid;
34
+ else
35
+ latMin = mid;
36
+ }
37
+ else {
38
+ if (isLon)
39
+ lonMax = mid;
40
+ else
41
+ latMax = mid;
42
+ }
43
+ isLon = !isLon;
44
+ bit++;
45
+ if (bit === 5) {
46
+ hash += BASE32[ch];
47
+ bit = 0;
48
+ ch = 0;
49
+ }
50
+ }
51
+ return hash;
52
+ }
@@ -1,3 +1,6 @@
1
1
  export { _cleanStringPII, _recursiveObjectClean } from "./data-structures.js";
2
+ export { encodeGeohash } from "./geohash.js";
3
+ export { getGeoAttributes, getGeoAttributesFromContext, createGeoAttributesFrom, } from "./geo-context.js";
4
+ export type { GeoAttributes, GeoInput, geoBaggageKeys } from "./geo-context.js";
2
5
  export { _containsEncodedComponents } from "./string-decoding.js";
3
6
  export { selfContainedSpanHandlerGenerator } from "./traces.js";
@@ -1,3 +1,5 @@
1
1
  export { _cleanStringPII, _recursiveObjectClean } from "./data-structures.js";
2
+ export { encodeGeohash } from "./geohash.js";
3
+ export { getGeoAttributes, getGeoAttributesFromContext, createGeoAttributesFrom, } from "./geo-context.js";
2
4
  export { _containsEncodedComponents } from "./string-decoding.js";
3
5
  export { selfContainedSpanHandlerGenerator } from "./traces.js";
@@ -1,10 +1,11 @@
1
1
  import buildNodeInstrumentation from "./lib/instrumentation.node.js";
2
2
  export type { Span, SpanStatus } from "@opentelemetry/api";
3
- export { SpanKind, SpanStatusCode, TraceFlags, Exception, } from "@opentelemetry/api";
3
+ export { SpanKind, SpanStatusCode, TraceFlags, type Exception, } from "@opentelemetry/api";
4
4
  export type * from "./lib/index.js";
5
5
  export type { NodeSDK } from "@opentelemetry/sdk-node";
6
6
  export { buildNodeInstrumentation as instrumentNode };
7
7
  export * from "./lib/processor/on-ending-hook-span-processor.js";
8
8
  export * from "./lib/metrics.js";
9
9
  export * from "./lib/traces.js";
10
+ export * from "./lib/geo/index.js";
10
11
  export * from "../sdk-core/index.js";
@@ -4,4 +4,5 @@ export { buildNodeInstrumentation as instrumentNode };
4
4
  export * from "./lib/processor/on-ending-hook-span-processor.js";
5
5
  export * from "./lib/metrics.js";
6
6
  export * from "./lib/traces.js";
7
+ export * from "./lib/geo/index.js";
7
8
  export * from "../sdk-core/index.js";
@@ -0,0 +1,6 @@
1
+ import { type Context, type TextMapGetter, type TextMapPropagator, type TextMapSetter } from "@opentelemetry/api";
2
+ export declare class GeoBaggagePropagator implements TextMapPropagator {
3
+ extract(ctx: Context, carrier: unknown, getter: TextMapGetter): Context;
4
+ inject(ctx: Context, carrier: unknown, setter: TextMapSetter): void;
5
+ fields(): string[];
6
+ }
@@ -0,0 +1,62 @@
1
+ import { propagation, } from "@opentelemetry/api";
2
+ import { encodeGeohash } from "../../../sdk-core/lib/utils/geohash.js";
3
+ import { geoBaggageKeys, } from "../../../sdk-core/lib/utils/geo-context.js";
4
+ const CF_HEADER_LATITUDE = "cloudfront-viewer-latitude";
5
+ const CF_HEADER_LONGITUDE = "cloudfront-viewer-longitude";
6
+ const CF_HEADER_CITY = "cloudfront-viewer-city";
7
+ const CF_HEADER_COUNTRY = "cloudfront-viewer-country";
8
+ const CF_FIELDS = [
9
+ CF_HEADER_COUNTRY,
10
+ CF_HEADER_CITY,
11
+ CF_HEADER_LATITUDE,
12
+ CF_HEADER_LONGITUDE,
13
+ ];
14
+ const getHash = (latStr, lonStr) => {
15
+ if (!latStr || !lonStr)
16
+ return undefined;
17
+ const lat = parseFloat(latStr);
18
+ const lon = parseFloat(lonStr);
19
+ if (!Number.isFinite(lat) || !Number.isFinite(lon))
20
+ return undefined;
21
+ return encodeGeohash(lat, lon, 4);
22
+ };
23
+ function getHeader(carrier, getter, key) {
24
+ const value = getter.get(carrier, key);
25
+ return Array.isArray(value) ? value[0] : value;
26
+ }
27
+ export class GeoBaggagePropagator {
28
+ extract(ctx, carrier, getter) {
29
+ const existingBaggage = propagation.getBaggage(ctx);
30
+ for (const key of geoBaggageKeys) {
31
+ if (existingBaggage?.getEntry(key))
32
+ return ctx;
33
+ }
34
+ const country = getHeader(carrier, getter, CF_HEADER_COUNTRY);
35
+ const city = getHeader(carrier, getter, CF_HEADER_CITY);
36
+ const latStr = getHeader(carrier, getter, CF_HEADER_LATITUDE);
37
+ const lonStr = getHeader(carrier, getter, CF_HEADER_LONGITUDE);
38
+ const attrs = {};
39
+ if (country)
40
+ attrs["geo.country"] = country;
41
+ if (city)
42
+ attrs["geo.city"] = city;
43
+ const hash = getHash(latStr, lonStr);
44
+ if (hash)
45
+ attrs["geo.hash"] = hash;
46
+ if (Object.keys(attrs).length === 0)
47
+ return ctx;
48
+ let baggage = propagation.getBaggage(ctx) ?? propagation.createBaggage();
49
+ for (const [key, value] of Object.entries(attrs)) {
50
+ baggage = baggage.setEntry(key, { value });
51
+ }
52
+ return propagation.setBaggage(ctx, baggage);
53
+ }
54
+ inject(ctx, carrier, setter) {
55
+ void ctx;
56
+ void carrier;
57
+ void setter;
58
+ }
59
+ fields() {
60
+ return [...CF_FIELDS];
61
+ }
62
+ }
@@ -0,0 +1,5 @@
1
+ export { getGeoAttributes, getGeoAttributesFromContext, createGeoAttributesFrom, } from "../../../sdk-core/lib/utils/geo-context.js";
2
+ export type { GeoAttributes, GeoInput, } from "../../../sdk-core/lib/utils/geo-context.js";
3
+ export { GeoBaggagePropagator } from "./geo-baggage-propagator.js";
4
+ export { GeoEnrichLogProcessor } from "../processor/geo-enrich-log-processor.js";
5
+ export { GeoEnrichSpanProcessor } from "../processor/geo-enrich-span-processor.js";
@@ -0,0 +1,4 @@
1
+ export { getGeoAttributes, getGeoAttributesFromContext, createGeoAttributesFrom, } from "../../../sdk-core/lib/utils/geo-context.js";
2
+ export { GeoBaggagePropagator } from "./geo-baggage-propagator.js";
3
+ export { GeoEnrichLogProcessor } from "../processor/geo-enrich-log-processor.js";
4
+ export { GeoEnrichSpanProcessor } from "../processor/geo-enrich-span-processor.js";
@@ -1,10 +1,10 @@
1
1
  import type { Metadata } from "@grpc/grpc-js";
2
2
  import { BasicRedactor } from "../../sdk-core/lib/index.js";
3
- import { InstrumentationConfigMap } from "@opentelemetry/auto-instrumentations-node";
4
- import { Instrumentation } from "@opentelemetry/instrumentation";
5
- import { Sampler, SpanProcessor } from "@opentelemetry/sdk-trace-base";
6
- import { BufferConfig, LogRecordProcessor } from "@opentelemetry/sdk-logs";
7
- import { ContextManager, TextMapPropagator } from "@opentelemetry/api";
3
+ import type { InstrumentationConfigMap } from "@opentelemetry/auto-instrumentations-node";
4
+ import type { Instrumentation } from "@opentelemetry/instrumentation";
5
+ import type { Sampler, SpanProcessor } from "@opentelemetry/sdk-trace-base";
6
+ import type { BufferConfig, LogRecordProcessor } from "@opentelemetry/sdk-logs";
7
+ import type { ContextManager, TextMapPropagator } from "@opentelemetry/api";
8
8
  import { NodeSDK } from "@opentelemetry/sdk-node";
9
9
  interface BaseNodeSDKConfig {
10
10
  /**
@@ -159,6 +159,18 @@ interface BaseNodeSDKConfig {
159
159
  * @param sdk The started NodeSDK instance.
160
160
  */
161
161
  onSdkStarted?: (sdk: NodeSDK) => void;
162
+ /**
163
+ * Configuration for geo enrichment from CloudFront headers.
164
+ *
165
+ * @default enabled
166
+ */
167
+ geoEnrichment?: {
168
+ /**
169
+ * Enable or disable geo enrichment from CloudFront headers.
170
+ * @default true
171
+ */
172
+ enabled: boolean;
173
+ };
162
174
  }
163
175
  /**
164
176
  * Configuration for batch collector mode (default).
@@ -1 +1,2 @@
1
- export {};
1
+ import { BasicRedactor } from "../../sdk-core/lib/index.js";
2
+ import { NodeSDK } from "@opentelemetry/sdk-node";
@@ -1,12 +1,15 @@
1
1
  import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
2
2
  import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
3
- import { CompositePropagator, W3CTraceContextPropagator, } from "@opentelemetry/core";
3
+ import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator, } from "@opentelemetry/core";
4
4
  import { NodeSDK } from "@opentelemetry/sdk-node";
5
5
  import { AlwaysOffSampler, ParentBasedSampler, TraceIdRatioBasedSampler, } from "@opentelemetry/sdk-trace-base";
6
6
  import { setNodeSdkConfig } from "./config-manager.js";
7
7
  import buildConsoleExporters from "./exporter/console.js";
8
8
  import buildGrpcExporters from "./exporter/grpc.js";
9
9
  import buildHttpExporters from "./exporter/http.js";
10
+ import { GeoBaggagePropagator } from "./geo/geo-baggage-propagator.js";
11
+ import { GeoEnrichLogProcessor } from "./processor/geo-enrich-log-processor.js";
12
+ import { GeoEnrichSpanProcessor } from "./processor/geo-enrich-span-processor.js";
10
13
  import { _shutdownHook } from "./internals/hooks.js";
11
14
  import { ObservabilityResourceDetector } from "./resource.js";
12
15
  import { UrlSampler } from "./url-sampler.js";
@@ -50,14 +53,17 @@ export default async function buildNodeInstrumentation(config) {
50
53
  else {
51
54
  exporter = await buildGrpcExporters(config);
52
55
  }
56
+ const geoEnabled = config.geoEnrichment?.enabled !== false;
53
57
  // Build span processors with custom processors from config
54
58
  const spanProcessors = [
55
59
  ...(config.prependSpanProcessors ?? []),
60
+ ...(geoEnabled ? [new GeoEnrichSpanProcessor()] : []),
56
61
  ...exporter.spans,
57
62
  ];
58
63
  // Build log processors with custom processors from config
59
64
  const logProcessors = [
60
65
  ...(config.prependLogProcessors ?? []),
66
+ ...(geoEnabled ? [new GeoEnrichLogProcessor()] : []),
61
67
  ...exporter.logs,
62
68
  ];
63
69
  const sdk = new NodeSDK({
@@ -72,6 +78,9 @@ export default async function buildNodeInstrumentation(config) {
72
78
  textMapPropagator: new CompositePropagator({
73
79
  propagators: [
74
80
  new W3CTraceContextPropagator(),
81
+ ...(geoEnabled
82
+ ? [new W3CBaggagePropagator(), new GeoBaggagePropagator()]
83
+ : []),
75
84
  ...(config.additionalPropagators ?? []),
76
85
  ],
77
86
  }),
@@ -1,16 +1,4 @@
1
1
  import type { NodeSDKConfig } from "../../../index.js";
2
- import type { Attributes } from "@opentelemetry/api";
3
2
  import { BasicRedactor } from "../../../../../sdk-core/index.js";
4
- export type PIISource = "trace" | "log" | "metric";
5
- export interface RedactionMetric extends Attributes {
6
- /** Type of PII redacted (e.g., "email", "phone"). */
7
- pii_type: string;
8
- /** Domain part of the redacted PII (e.g., "gmail.com"). */
9
- pii_email_domain?: string;
10
- /** Source of the redaction (trace, log or metric). */
11
- redaction_source: PIISource;
12
- /** Format or structure of the redacted value. */
13
- pii_format: "string" | "url";
14
- }
15
3
  export type RedactorKeys = keyof Omit<NonNullable<NodeSDKConfig["detection"]>, "custom">;
16
4
  export declare const redactors: Record<RedactorKeys, BasicRedactor>;
@@ -1,13 +1,6 @@
1
- import { EmailRedactorWithMetrics } from "./email.js";
2
- import { IpRedactorWithMetrics } from "./ip.js";
3
- import { getMetric } from "../../../metrics.js";
4
- import { PpsnRedactorWithMetrics } from "./ppsn.js";
5
- const metricCounter = getMetric("counter", {
6
- meterName: "o11y",
7
- metricName: "o11y_pii_redaction",
8
- });
1
+ import { BasicRedactor, EmailRedactor, IpRedactor, PpsnRedactor, } from "../../../../../sdk-core/index.js";
9
2
  export const redactors = {
10
- email: new EmailRedactorWithMetrics(metricCounter),
11
- ip: new IpRedactorWithMetrics(metricCounter),
12
- ppsn: new PpsnRedactorWithMetrics(metricCounter),
3
+ email: new EmailRedactor(),
4
+ ip: new IpRedactor(),
5
+ ppsn: new PpsnRedactor(),
13
6
  };
@@ -1,4 +1,6 @@
1
1
  import { createNoopMeter, metrics, } from "@opentelemetry/api";
2
+ import { getGeoAttributes } from "../../sdk-core/lib/utils/geo-context.js";
3
+ import { getNodeSdkConfig } from "./config-manager.js";
2
4
  const MetricsFactoryMap = {
3
5
  gauge: (meter) => meter.createGauge,
4
6
  histogram: (meter) => meter.createHistogram,
@@ -20,5 +22,29 @@ export function getMetric(type, p) {
20
22
  if (!MetricsFactoryMap[type]) {
21
23
  throw new Error(`Unsupported metric type: ${type}`);
22
24
  }
23
- return MetricsFactoryMap[type](meter).bind(meter)(p.metricName, p.options);
25
+ const instrument = MetricsFactoryMap[type](meter).bind(meter)(p.metricName, p.options);
26
+ const geoEnabled = getNodeSdkConfig()?.geoEnrichment?.enabled !== false;
27
+ if (!geoEnabled || type.startsWith("async-")) {
28
+ return instrument;
29
+ }
30
+ return wrapWithGeoAttributes(instrument);
31
+ }
32
+ function wrapWithGeoAttributes(instrument) {
33
+ if (typeof instrument !== "object" || instrument === null) {
34
+ return instrument;
35
+ }
36
+ return new Proxy(instrument, {
37
+ get(target, prop, receiver) {
38
+ const value = Reflect.get(target, prop, receiver);
39
+ if (typeof value !== "function")
40
+ return value;
41
+ if (prop === "add" || prop === "record") {
42
+ return (amount, attributes, ...rest) => {
43
+ const merged = { ...getGeoAttributes(), ...attributes };
44
+ return value.call(target, amount, merged, ...rest);
45
+ };
46
+ }
47
+ return value.bind(target);
48
+ },
49
+ });
24
50
  }
@@ -1,4 +1,4 @@
1
- import { NodeSDKConfig } from "../index.js";
1
+ import type { NodeSDKConfig } from "../index.js";
2
2
  import type { NodeOptions as SentryNodeOptions } from "@sentry/node";
3
3
  /**
4
4
  * Options for the withSentry preset function.
@@ -0,0 +1,7 @@
1
+ import type { SdkLogRecord, LogRecordProcessor } from "@opentelemetry/sdk-logs";
2
+ import { type Context } from "@opentelemetry/api";
3
+ export declare class GeoEnrichLogProcessor implements LogRecordProcessor {
4
+ forceFlush(): Promise<void>;
5
+ onEmit(logRecord: SdkLogRecord, logContext?: Context): void;
6
+ shutdown(): Promise<void>;
7
+ }
@@ -0,0 +1,18 @@
1
+ import { context } from "@opentelemetry/api";
2
+ import { getGeoAttributesFromContext } from "../../../sdk-core/lib/utils/geo-context.js";
3
+ export class GeoEnrichLogProcessor {
4
+ forceFlush() {
5
+ return Promise.resolve();
6
+ }
7
+ onEmit(logRecord, logContext) {
8
+ const geoAttrs = getGeoAttributesFromContext(logContext ?? context.active());
9
+ for (const [key, value] of Object.entries(geoAttrs)) {
10
+ if (value !== undefined) {
11
+ logRecord.setAttribute(key, value);
12
+ }
13
+ }
14
+ }
15
+ shutdown() {
16
+ return Promise.resolve();
17
+ }
18
+ }
@@ -0,0 +1,8 @@
1
+ import type { Context } from "@opentelemetry/api";
2
+ import type { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base";
3
+ export declare class GeoEnrichSpanProcessor implements SpanProcessor {
4
+ forceFlush(): Promise<void>;
5
+ onStart(span: Span, parentContext: Context): void;
6
+ onEnd(_span: ReadableSpan): void;
7
+ shutdown(): Promise<void>;
8
+ }
@@ -0,0 +1,18 @@
1
+ import { getGeoAttributesFromContext } from "../../../sdk-core/lib/utils/geo-context.js";
2
+ export class GeoEnrichSpanProcessor {
3
+ forceFlush() {
4
+ return Promise.resolve();
5
+ }
6
+ onStart(span, parentContext) {
7
+ const geoAttrs = getGeoAttributesFromContext(parentContext);
8
+ for (const [key, value] of Object.entries(geoAttrs)) {
9
+ if (value !== undefined) {
10
+ span.setAttribute(key, value);
11
+ }
12
+ }
13
+ }
14
+ onEnd(_span) { }
15
+ shutdown() {
16
+ return Promise.resolve();
17
+ }
18
+ }
@@ -1,5 +1,5 @@
1
- import { Context } from "@opentelemetry/api";
2
- import { LogRecordProcessor, SdkLogRecord } from "@opentelemetry/sdk-logs";
1
+ import type { Context } from "@opentelemetry/api";
2
+ import type { LogRecordProcessor, SdkLogRecord } from "@opentelemetry/sdk-logs";
3
3
  export declare class NextJsLogProcessor implements LogRecordProcessor {
4
4
  onEmit(logRecord: SdkLogRecord, _context?: Context): void;
5
5
  shutdown(): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { Span } from "@opentelemetry/sdk-trace-base";
1
+ import type { Span } from "@opentelemetry/sdk-trace-base";
2
2
  import { OnEndingHookSpanProcessor } from "./on-ending-hook-span-processor.js";
3
3
  export declare class NextJsSpanProcessor extends OnEndingHookSpanProcessor {
4
4
  onEnding(span: Span): void;
@@ -1,5 +1,5 @@
1
- import { Context } from "@opentelemetry/api";
2
- import { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base";
1
+ import type { Context } from "@opentelemetry/api";
2
+ import type { ReadableSpan, Span, SpanProcessor } from "@opentelemetry/sdk-trace-base";
3
3
  /**
4
4
  * A SpanProcessor that provides a hook to execute custom logic
5
5
  * just before a span is ended.
@@ -1,3 +1,4 @@
1
+ import { SpanKind, } from "@opentelemetry/api";
1
2
  import { SamplingDecision, } from "@opentelemetry/sdk-trace-base";
2
3
  export class UrlSampler {
3
4
  _samplerCondition;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogcio/o11y-sdk-node",
3
- "version": "0.11.2",
3
+ "version": "0.11.4",
4
4
  "description": "Opentelemetry standard instrumentation SDK for NodeJS based project",
5
5
  "main": "dist/sdk-node/index.js",
6
6
  "types": "dist/sdk-node/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogcio/o11y-sdk-node",
3
- "version": "0.11.2",
3
+ "version": "0.11.4",
4
4
  "description": "Opentelemetry standard instrumentation SDK for NodeJS based project",
5
5
  "main": "dist/sdk-node/index.js",
6
6
  "types": "dist/sdk-node/index.d.ts",
@@ -1,8 +0,0 @@
1
- import type { PIISource, RedactionMetric } from "./index.js";
2
- import type { Counter } from "@opentelemetry/api";
3
- import { EmailRedactor, type StringKind } from "../../../../../sdk-core/index.js";
4
- export declare class EmailRedactorWithMetrics extends EmailRedactor {
5
- protected _counterRedactionMetric: Counter<RedactionMetric>;
6
- constructor(metric: Counter<RedactionMetric>);
7
- protected exportMetrics(context: ReturnType<typeof this.redact>["context"], source: PIISource, kind: StringKind): void;
8
- }
@@ -1,19 +0,0 @@
1
- import { EmailRedactor, } from "../../../../../sdk-core/index.js";
2
- export class EmailRedactorWithMetrics extends EmailRedactor {
3
- _counterRedactionMetric;
4
- constructor(metric) {
5
- super();
6
- this._counterRedactionMetric = metric;
7
- }
8
- exportMetrics(context, source, kind) {
9
- const { domains } = context;
10
- for (const [domain, domainCount] of Object.entries(domains)) {
11
- this._counterRedactionMetric.add(domainCount, {
12
- pii_type: "email",
13
- redaction_source: source,
14
- pii_email_domain: domain,
15
- pii_format: kind,
16
- });
17
- }
18
- }
19
- }
@@ -1,8 +0,0 @@
1
- import type { Counter } from "@opentelemetry/api";
2
- import type { PIISource, RedactionMetric } from "./index.js";
3
- import { IpRedactor, type StringKind } from "../../../../../sdk-core/index.js";
4
- export declare class IpRedactorWithMetrics extends IpRedactor {
5
- protected _counterRedactionMetric: Counter<RedactionMetric>;
6
- constructor(metric: Counter<RedactionMetric>);
7
- protected exportMetrics(context: ReturnType<typeof this.redact>["context"], source: PIISource, kind: StringKind): void;
8
- }
@@ -1,20 +0,0 @@
1
- import { IpRedactor } from "../../../../../sdk-core/index.js";
2
- export class IpRedactorWithMetrics extends IpRedactor {
3
- _counterRedactionMetric;
4
- constructor(metric) {
5
- super();
6
- this._counterRedactionMetric = metric;
7
- }
8
- exportMetrics(context, source, kind) {
9
- const { counters } = context;
10
- Object.entries(counters).forEach(([type, counter]) => {
11
- if (counter > 0) {
12
- this._counterRedactionMetric.add(counter, {
13
- pii_type: type,
14
- redaction_source: source,
15
- pii_format: kind,
16
- });
17
- }
18
- });
19
- }
20
- }
@@ -1,8 +0,0 @@
1
- import type { PIISource, RedactionMetric } from "./index.js";
2
- import type { Counter } from "@opentelemetry/api";
3
- import { PpsnRedactor, type StringKind } from "../../../../../sdk-core/index.js";
4
- export declare class PpsnRedactorWithMetrics extends PpsnRedactor {
5
- protected _counterRedactionMetric: Counter<RedactionMetric>;
6
- constructor(metric: Counter<RedactionMetric>);
7
- protected exportMetrics(context: ReturnType<typeof this.redact>["context"], source: PIISource, kind: StringKind): void;
8
- }
@@ -1,18 +0,0 @@
1
- import { PpsnRedactor, } from "../../../../../sdk-core/index.js";
2
- export class PpsnRedactorWithMetrics extends PpsnRedactor {
3
- _counterRedactionMetric;
4
- constructor(metric) {
5
- super();
6
- this._counterRedactionMetric = metric;
7
- }
8
- exportMetrics(context, source, kind) {
9
- const { redactedCounter } = context;
10
- if (redactedCounter === 0)
11
- return;
12
- this._counterRedactionMetric.add(redactedCounter, {
13
- pii_type: "ppsn",
14
- redaction_source: source,
15
- pii_format: kind,
16
- });
17
- }
18
- }