Skip to content

Commit e965f04

Browse files
committed
Support per-signal OTLP exporter endpoints
This change allows for more granular control over OpenTelemetry data routing by enabling independent configuration of traces, metrics, and logs endpoints. This is particularly useful for complex networking environments or when using different backends for different telemetry types. Additionally, the browser instrumentation has been updated to a local wrapper to better manage these signal-specific configurations and improve internal consistency.
1 parent bdca9bd commit e965f04

11 files changed

Lines changed: 191 additions & 21 deletions

File tree

docker-compose.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ services:
6262
SERVER_URL: http://127.0.0.1:${HYPERDX_API_PORT}
6363
OPAMP_PORT: ${HYPERDX_OPAMP_PORT}
6464
OTEL_EXPORTER_OTLP_ENDPOINT: 'http://otel-collector:4318'
65+
# Per-signal OTLP endpoints (override OTEL_EXPORTER_OTLP_ENDPOINT for individual signals)
66+
# OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: 'http://otel-collector:4318/v1/traces'
67+
# OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: 'http://otel-collector:4318/v1/metrics'
68+
# OTEL_EXPORTER_OTLP_LOGS_ENDPOINT: 'http://otel-collector:4318/v1/logs'
6569
OTEL_SERVICE_NAME: 'hdx-oss-app'
6670
USAGE_STATS_ENABLED: ${USAGE_STATS_ENABLED:-true}
6771
DEFAULT_CONNECTIONS:

packages/api/.env.development

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ NODE_ENV=development
1111
OTEL_SERVICE_NAME="hdx-oss-dev-api"
1212
OTEL_RESOURCE_ATTRIBUTES="service.version=dev"
1313
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${HDX_DEV_OTEL_HTTP_PORT}"
14+
# Per-signal OTLP endpoints (override the base endpoint for individual signals)
15+
# OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=
16+
# OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=
17+
# OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=
1418
PORT=${HYPERDX_API_PORT}
1519
OPAMP_PORT=${HYPERDX_OPAMP_PORT}
1620
REDIS_URL=redis://localhost:6379

packages/app/.env.development

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,8 @@ OTEL_SERVICE_NAME="hdx-oss-dev-app"
77
PORT=${HYPERDX_APP_PORT}
88
NODE_OPTIONS="--max-http-header-size=131072"
99
NEXT_PUBLIC_HYPERDX_BASE_PATH=
10-
NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${HDX_DEV_OTEL_HTTP_PORT:-4318}"
10+
NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:${HDX_DEV_OTEL_HTTP_PORT:-4318}"
11+
# Per-signal OTLP endpoints (override the base endpoint for individual signals)
12+
# NEXT_PUBLIC_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=
13+
# NEXT_PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=
14+
# NEXT_PUBLIC_OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=

packages/app/Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,15 @@ COPY --from=common-utils-builder /app/packages/common-utils ./packages/common-ut
4343
# Expose custom env variables to the browser (needs NEXT_PUBLIC_ prefix)
4444
# doc: https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables#bundling-environment-variables-for-the-browser
4545
ARG OTEL_EXPORTER_OTLP_ENDPOINT
46+
ARG OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
47+
ARG OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
48+
ARG OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
4649
ARG OTEL_SERVICE_NAME
4750
ARG IS_LOCAL_MODE
4851
ENV NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT $OTEL_EXPORTER_OTLP_ENDPOINT
52+
ENV NEXT_PUBLIC_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT $OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
53+
ENV NEXT_PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT $OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
54+
ENV NEXT_PUBLIC_OTEL_EXPORTER_OTLP_LOGS_ENDPOINT $OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
4955
ENV NEXT_PUBLIC_OTEL_SERVICE_NAME $OTEL_SERVICE_NAME
5056
ENV NEXT_PUBLIC_IS_LOCAL_MODE $IS_LOCAL_MODE
5157

packages/app/pages/_app.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { NextAdapter } from 'next-query-params';
66
import randomUUID from 'crypto-randomuuid';
77
import { enableMapSet } from 'immer';
88
import { QueryParamProvider } from 'use-query-params';
9-
import HyperDX from '@hyperdx/browser';
109
import {
1110
MutationCache,
1211
QueryCache,
@@ -23,6 +22,7 @@ import {
2322
MANTINE_FONT_MAP,
2423
} from '@/config/fonts';
2524
import { ibmPlexMono, inter, roboto, robotoMono } from '@/fonts';
25+
import HyperDX from '@/hdx-browser';
2626
import { AppThemeProvider, useAppTheme } from '@/theme/ThemeProvider';
2727
import { ThemeWrapper } from '@/ThemeWrapper';
2828
import { NextApiConfigResponseData } from '@/types';
@@ -147,6 +147,8 @@ export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
147147
service: _jsonData.serviceName,
148148
// tracePropagationTargets: [new RegExp(hostname ?? 'localhost', 'i')],
149149
url: _jsonData.collectorUrl,
150+
tracesUrl: _jsonData.collectorTracesUrl,
151+
logsUrl: _jsonData.collectorLogsUrl,
150152
});
151153
} else {
152154
console.warn('No API key found to enable OTEL exporter');

packages/app/pages/api/config.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ import {
44
HDX_API_KEY,
55
HDX_COLLECTOR_URL,
66
HDX_EXPORTER_ENABLED,
7+
HDX_LOGS_COLLECTOR_URL,
8+
HDX_METRICS_COLLECTOR_URL,
79
HDX_SERVICE_NAME,
10+
HDX_TRACES_COLLECTOR_URL,
811
} from '@/config';
912
import type { NextApiConfigResponseData } from '@/types';
1013

@@ -15,6 +18,9 @@ export default function handler(
1518
res.status(200).json({
1619
apiKey: HDX_EXPORTER_ENABLED ? HDX_API_KEY : undefined,
1720
collectorUrl: HDX_COLLECTOR_URL,
21+
collectorTracesUrl: HDX_TRACES_COLLECTOR_URL,
22+
collectorMetricsUrl: HDX_METRICS_COLLECTOR_URL,
23+
collectorLogsUrl: HDX_LOGS_COLLECTOR_URL,
1824
serviceName: HDX_SERVICE_NAME,
1925
appVersion: process.env.NEXT_PUBLIC_APP_VERSION,
2026
});

packages/app/src/components/AppNav/AppNav.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useCallback, useEffect, useMemo } from 'react';
22
import Link from 'next/link';
33
import Router, { useRouter } from 'next/router';
44
import cx from 'classnames';
5-
import HyperDX from '@hyperdx/browser';
65
import { isBuilderSavedChartConfig } from '@hyperdx/common-utils/dist/guards';
76
import {
87
AlertState,
@@ -36,6 +35,7 @@ import { AlertStatusIcon } from '@/components/AlertStatusIcon';
3635
import { IS_LOCAL_MODE } from '@/config';
3736
import { Dashboard, useDashboards } from '@/dashboard';
3837
import { useFavorites } from '@/favorites';
38+
import HyperDX from '@/hdx-browser';
3939
import InstallInstructionModal from '@/InstallInstructionsModal';
4040
import OnboardingChecklist from '@/OnboardingChecklist';
4141
import { useSavedSearches } from '@/savedSearch';

packages/app/src/config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ export const HDX_COLLECTOR_URL =
1818
process.env.NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT ??
1919
process.env.OTEL_EXPORTER_OTLP_ENDPOINT ??
2020
'http://localhost:4318';
21+
export const HDX_TRACES_COLLECTOR_URL =
22+
process.env.NEXT_PUBLIC_OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ??
23+
process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT;
24+
export const HDX_METRICS_COLLECTOR_URL =
25+
process.env.NEXT_PUBLIC_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ??
26+
process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT;
27+
export const HDX_LOGS_COLLECTOR_URL =
28+
process.env.NEXT_PUBLIC_OTEL_EXPORTER_OTLP_LOGS_ENDPOINT ??
29+
process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT;
2130
export const IS_DEV = NODE_ENV === 'development';
2231

2332
export const IS_OSS = process.env.NEXT_PUBLIC_IS_OSS ?? 'true' === 'true';

packages/app/src/hdx-browser.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import Rum from '@hyperdx/otel-web';
2+
import SessionRecorder from '@hyperdx/otel-web-session-recorder';
3+
import type { Attributes } from '@opentelemetry/api';
4+
import type { ResourceAttributes } from '@opentelemetry/resources';
5+
6+
type InitConfig = {
7+
advancedNetworkCapture?: boolean;
8+
apiKey: string;
9+
blockClass?: string;
10+
consoleCapture?: boolean;
11+
debug?: boolean;
12+
disableReplay?: boolean;
13+
ignoreClass?: string;
14+
maskAllInputs?: boolean;
15+
maskAllText?: boolean;
16+
maskClass?: string;
17+
recordCanvas?: boolean;
18+
sampling?: Parameters<typeof SessionRecorder.init>[0]['sampling'];
19+
service: string;
20+
tracePropagationTargets?: (string | RegExp)[];
21+
url?: string;
22+
tracesUrl?: string;
23+
logsUrl?: string;
24+
otelResourceAttributes?: ResourceAttributes;
25+
};
26+
27+
const DEFAULT_URL = 'https://in-otel.hyperdx.io';
28+
29+
let _advancedNetworkCapture = false;
30+
31+
function init({
32+
advancedNetworkCapture = false,
33+
apiKey,
34+
blockClass,
35+
consoleCapture = false,
36+
debug = false,
37+
disableReplay = false,
38+
ignoreClass,
39+
maskAllInputs = true,
40+
maskAllText = false,
41+
maskClass,
42+
recordCanvas = false,
43+
sampling,
44+
service,
45+
tracePropagationTargets,
46+
url,
47+
tracesUrl,
48+
logsUrl,
49+
otelResourceAttributes,
50+
}: InitConfig): void {
51+
if (typeof window === 'undefined') {
52+
return;
53+
}
54+
55+
const urlBase = url ?? DEFAULT_URL;
56+
const resolvedTracesUrl = tracesUrl ?? `${urlBase}/v1/traces`;
57+
const resolvedLogsUrl = logsUrl ?? `${urlBase}/v1/logs`;
58+
59+
_advancedNetworkCapture = advancedNetworkCapture;
60+
61+
Rum.init({
62+
debug,
63+
url: resolvedTracesUrl,
64+
allowInsecureUrl: true,
65+
apiKey,
66+
applicationName: service,
67+
globalAttributes: otelResourceAttributes as Attributes | undefined,
68+
instrumentations: {
69+
visibility: true,
70+
console: consoleCapture,
71+
fetch: {
72+
...(tracePropagationTargets != null
73+
? { propagateTraceHeaderCorsUrls: tracePropagationTargets }
74+
: {}),
75+
advancedNetworkCapture: () => _advancedNetworkCapture,
76+
},
77+
xhr: {
78+
...(tracePropagationTargets != null
79+
? { propagateTraceHeaderCorsUrls: tracePropagationTargets }
80+
: {}),
81+
advancedNetworkCapture: () => _advancedNetworkCapture,
82+
},
83+
},
84+
});
85+
86+
if (!disableReplay) {
87+
SessionRecorder.init({
88+
apiKey,
89+
blockClass,
90+
debug,
91+
ignoreClass,
92+
maskAllInputs,
93+
maskTextClass: maskClass,
94+
maskTextSelector: maskAllText ? '*' : undefined,
95+
recordCanvas,
96+
sampling,
97+
url: resolvedLogsUrl,
98+
});
99+
}
100+
}
101+
102+
function addAction(name: string, attributes?: Attributes): void {
103+
if (typeof window === 'undefined') return;
104+
Rum.addAction(name, attributes);
105+
}
106+
107+
function setGlobalAttributes(attributes: Record<string, string>): void {
108+
if (typeof window === 'undefined') return;
109+
Rum.setGlobalAttributes(attributes);
110+
}
111+
112+
function enableAdvancedNetworkCapture(): void {
113+
_advancedNetworkCapture = true;
114+
}
115+
116+
function getSessionId(): string | undefined {
117+
return Rum.getSessionId();
118+
}
119+
120+
function recordException(error: any, attributes?: Attributes): void {
121+
if (typeof window === 'undefined') return;
122+
Rum.recordException(error, attributes);
123+
}
124+
125+
const HyperDXBrowser = {
126+
init,
127+
addAction,
128+
setGlobalAttributes,
129+
enableAdvancedNetworkCapture,
130+
getSessionId,
131+
recordException,
132+
};
133+
134+
export default HyperDXBrowser;

packages/app/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ export enum KubePhase {
139139
export type NextApiConfigResponseData = {
140140
apiKey?: string;
141141
collectorUrl: string;
142+
collectorTracesUrl?: string;
143+
collectorMetricsUrl?: string;
144+
collectorLogsUrl?: string;
142145
serviceName: string;
143146
appVersion?: string;
144147
};

0 commit comments

Comments
 (0)