mirror of
https://github.com/vector-im/element-call.git
synced 2024-11-15 00:04:59 +08:00
Version that does at least send some traces
This commit is contained in:
parent
1e2cd97764
commit
c519e13885
@ -23,7 +23,6 @@
|
|||||||
"@opentelemetry/context-zone": "^1.9.1",
|
"@opentelemetry/context-zone": "^1.9.1",
|
||||||
"@opentelemetry/exporter-jaeger": "^1.9.1",
|
"@opentelemetry/exporter-jaeger": "^1.9.1",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.35.1",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.35.1",
|
||||||
"@opentelemetry/exporter-zipkin": "^1.9.1",
|
|
||||||
"@opentelemetry/instrumentation-document-load": "^0.31.1",
|
"@opentelemetry/instrumentation-document-load": "^0.31.1",
|
||||||
"@opentelemetry/instrumentation-user-interaction": "^0.32.1",
|
"@opentelemetry/instrumentation-user-interaction": "^0.32.1",
|
||||||
"@opentelemetry/sdk-trace-web": "^1.9.1",
|
"@opentelemetry/sdk-trace-web": "^1.9.1",
|
||||||
|
@ -15,18 +15,48 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import opentelemetry, { Context, Span } from "@opentelemetry/api";
|
import opentelemetry, { Context, Span } from "@opentelemetry/api";
|
||||||
import {
|
import { GroupCall, MatrixEvent } from "matrix-js-sdk";
|
||||||
ClientEvent,
|
import { VoipEvent } from "matrix-js-sdk/src/webrtc/call";
|
||||||
GroupCall,
|
|
||||||
MatrixClient,
|
|
||||||
MatrixEvent,
|
|
||||||
RoomStateEvent,
|
|
||||||
} from "matrix-js-sdk";
|
|
||||||
import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
|
|
||||||
import { useCallback, useEffect, useState } from "react";
|
|
||||||
|
|
||||||
import { tracer } from "./otel";
|
import { tracer } from "./otel";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively sets the contents of a todevice event object as attributes on a span
|
||||||
|
*/
|
||||||
|
function setNestedAttributesFromToDeviceEvent(span: Span, event: VoipEvent) {
|
||||||
|
setSpanEventAttributesRecursive(
|
||||||
|
span,
|
||||||
|
event as unknown as Record<string, unknown>, // XXX Types
|
||||||
|
"matrix.",
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSpanEventAttributesRecursive(
|
||||||
|
span: Span,
|
||||||
|
obj: Record<string, unknown>,
|
||||||
|
prefix: string,
|
||||||
|
depth: number
|
||||||
|
) {
|
||||||
|
if (depth > 10)
|
||||||
|
throw new Error(
|
||||||
|
"Depth limit exceeded: aborting VoipEvent recursion. Prefix is " + prefix
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(obj)) {
|
||||||
|
if (["string", "number"].includes(typeof v)) {
|
||||||
|
span.setAttribute(prefix + k, v as string | number);
|
||||||
|
} else if (typeof v === "object") {
|
||||||
|
setSpanEventAttributesRecursive(
|
||||||
|
span,
|
||||||
|
v as Record<string, unknown>,
|
||||||
|
prefix + k + ".",
|
||||||
|
depth + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represent the span of time which we intend to be joined to a group call
|
* Represent the span of time which we intend to be joined to a group call
|
||||||
*/
|
*/
|
||||||
@ -34,7 +64,7 @@ export class OTelGroupCallMembership {
|
|||||||
private context: Context;
|
private context: Context;
|
||||||
private callMembershipSpan: Span;
|
private callMembershipSpan: Span;
|
||||||
|
|
||||||
constructor(private groupCall: GroupCall) {
|
constructor(groupCall: GroupCall) {
|
||||||
const callIdContext = opentelemetry.context
|
const callIdContext = opentelemetry.context
|
||||||
.active()
|
.active()
|
||||||
.setValue(Symbol("confId"), groupCall.groupCallId);
|
.setValue(Symbol("confId"), groupCall.groupCallId);
|
||||||
@ -82,125 +112,19 @@ export class OTelGroupCallMembership {
|
|||||||
|
|
||||||
public onSendStateEvent(stateEvent: MatrixEvent) {}
|
public onSendStateEvent(stateEvent: MatrixEvent) {}
|
||||||
|
|
||||||
public onSendToDeviceEvent(toDeviceEvent: Record<string, unknown>) {
|
public onSendEvent(event: VoipEvent) {
|
||||||
const eventType = toDeviceEvent.eventType as string;
|
const eventType = event.eventType as string;
|
||||||
if (!eventType.startsWith("m.call")) return;
|
if (!eventType.startsWith("m.call")) return;
|
||||||
|
|
||||||
const span = tracer.startSpan(
|
if (event.type === "toDevice") {
|
||||||
`otel_sendToDeviceEvent_${toDeviceEvent.eventType}`,
|
const span = tracer.startSpan(
|
||||||
undefined,
|
`otel_sendToDeviceEvent_${event.eventType}`,
|
||||||
this.context
|
undefined,
|
||||||
);
|
this.context
|
||||||
|
);
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(toDeviceEvent)) {
|
setNestedAttributesFromToDeviceEvent(span, event);
|
||||||
if (["string", "number"].includes(typeof v))
|
span.end();
|
||||||
span.setAttribute(k, v as string | number);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useCallEventInstrumentation = (
|
|
||||||
client: MatrixClient,
|
|
||||||
groupCall: GroupCall
|
|
||||||
): void => {
|
|
||||||
const [groupCallSpan, setGroupCallSpan] = useState<Span | undefined>();
|
|
||||||
const [groupCallId, setGroupCallId] = useState<string | undefined>();
|
|
||||||
|
|
||||||
const startChildSpan = useCallback(
|
|
||||||
(name: string, groupCallId: string): Span => {
|
|
||||||
const traceId = "7b78c1f568312cb288e55a9bc3c28cc5";
|
|
||||||
const spanId = "7d31f3e430d90882";
|
|
||||||
|
|
||||||
const ctx = opentelemetry.trace.setSpanContext(context.active(), {
|
|
||||||
traceId,
|
|
||||||
spanId,
|
|
||||||
traceFlags: 1,
|
|
||||||
isRemote: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("LOG context", ctx);
|
|
||||||
console.log(
|
|
||||||
"LOG context valid",
|
|
||||||
trace.isSpanContextValid(trace.getSpan(ctx).spanContext())
|
|
||||||
);
|
|
||||||
console.log("LOG parent span", trace.getSpan(ctx));
|
|
||||||
|
|
||||||
return tracer.startSpan(name, undefined, ctx);
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onUpdateRoomState = useCallback((event?: MatrixEvent) => {
|
|
||||||
/*const callStateEvent = groupCall.room.currentState.getStateEvents(
|
|
||||||
"org.matrix.msc3401.call",
|
|
||||||
groupCall.groupCallId
|
|
||||||
);*/
|
|
||||||
/*const memberStateEvents = groupCall.room.currentState.getStateEvents(
|
|
||||||
"org.matrix.msc3401.call.member"
|
|
||||||
);*/
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onReceivedVoipEvent = (event: MatrixEvent) => {};
|
|
||||||
|
|
||||||
const onUndecryptableToDevice = (event: MatrixEvent) => {};
|
|
||||||
|
|
||||||
const onSendVoipEvent = useCallback(
|
|
||||||
(event: Record<string, unknown>) => {
|
|
||||||
const span = startChildSpan(
|
|
||||||
`element-call:send-voip-event:${event.eventType}`,
|
|
||||||
groupCall.groupCallId
|
|
||||||
);
|
|
||||||
span.setAttribute("groupCallId", groupCall.groupCallId);
|
|
||||||
|
|
||||||
console.log("LOG span", span);
|
|
||||||
|
|
||||||
span.end();
|
|
||||||
},
|
|
||||||
[groupCall.groupCallId, startChildSpan]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return;
|
|
||||||
if (groupCallId === groupCall.groupCallId) return;
|
|
||||||
|
|
||||||
console.log("LOG starting span", groupCall.groupCallId, groupCallId);
|
|
||||||
|
|
||||||
groupCallSpan?.end();
|
|
||||||
|
|
||||||
const newSpan = tracer.startSpan("element-call:group-call");
|
|
||||||
newSpan.setAttribute("groupCallId", groupCall.groupCallId);
|
|
||||||
setGroupCallSpan(newSpan);
|
|
||||||
setGroupCallId(groupCall.groupCallId);
|
|
||||||
}, [groupCallSpan, groupCallId, groupCall.groupCallId]);
|
|
||||||
|
|
||||||
useEffect(() => () => {
|
|
||||||
console.log("LOG ending span");
|
|
||||||
|
|
||||||
groupCallSpan?.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
client.on(RoomStateEvent.Events, onUpdateRoomState);
|
|
||||||
//groupCall.on("calls_changed", onCallsChanged);
|
|
||||||
groupCall.on(CallEvent.SendVoipEvent, onSendVoipEvent);
|
|
||||||
//client.on("state", onCallsChanged);
|
|
||||||
//client.on("hangup", onCallHangup);
|
|
||||||
client.on(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent);
|
|
||||||
client.on(ClientEvent.UndecryptableToDeviceEvent, onUndecryptableToDevice);
|
|
||||||
|
|
||||||
onUpdateRoomState();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
client.removeListener(RoomStateEvent.Events, onUpdateRoomState);
|
|
||||||
//groupCall.removeListener("calls_changed", onCallsChanged);
|
|
||||||
groupCall.removeListener(CallEvent.SendVoipEvent, onSendVoipEvent);
|
|
||||||
//client.removeListener("state", onCallsChanged);
|
|
||||||
//client.removeListener("hangup", onCallHangup);
|
|
||||||
client.removeListener(ClientEvent.ReceivedVoipEvent, onReceivedVoipEvent);
|
|
||||||
client.removeListener(
|
|
||||||
ClientEvent.UndecryptableToDeviceEvent,
|
|
||||||
onUndecryptableToDevice
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}, [client, groupCall, onSendVoipEvent, onUpdateRoomState]);
|
|
||||||
};
|
|
||||||
|
@ -6,7 +6,6 @@ import {
|
|||||||
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
||||||
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
|
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
|
||||||
import opentelemetry from "@opentelemetry/api";
|
import opentelemetry from "@opentelemetry/api";
|
||||||
import { Context } from "@opentelemetry/api";
|
|
||||||
import { Resource } from "@opentelemetry/resources";
|
import { Resource } from "@opentelemetry/resources";
|
||||||
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
|
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
|
||||||
|
|
||||||
@ -29,12 +28,14 @@ const provider = new WebTracerProvider(providerConfig);
|
|||||||
provider.addSpanProcessor(new SimpleSpanProcessor(otlpExporter));
|
provider.addSpanProcessor(new SimpleSpanProcessor(otlpExporter));
|
||||||
provider.addSpanProcessor(new SimpleSpanProcessor(posthogExporter));
|
provider.addSpanProcessor(new SimpleSpanProcessor(posthogExporter));
|
||||||
provider.addSpanProcessor(new SimpleSpanProcessor(consoleExporter));
|
provider.addSpanProcessor(new SimpleSpanProcessor(consoleExporter));
|
||||||
|
opentelemetry.trace.setGlobalTracerProvider(provider);
|
||||||
|
|
||||||
// This is not the serviceName shown in jaeger
|
// This is not the serviceName shown in jaeger
|
||||||
export const tracer = opentelemetry.trace.getTracer(
|
export const tracer = opentelemetry.trace.getTracer(
|
||||||
"my-element-call-otl-tracer"
|
"my-element-call-otl-tracer"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
class CallTracer {
|
class CallTracer {
|
||||||
// We create one tracer class for each main context.
|
// We create one tracer class for each main context.
|
||||||
// Even if differnt tracer classes overlap in time space, we might want to visulaize them seperately.
|
// Even if differnt tracer classes overlap in time space, we might want to visulaize them seperately.
|
||||||
@ -47,7 +48,7 @@ class CallTracer {
|
|||||||
|
|
||||||
public startGroupCall(groupCallId: string) {}
|
public startGroupCall(groupCallId: string) {}
|
||||||
|
|
||||||
public startCall(callId: string): Context {
|
public startCall(callId: string) {
|
||||||
// The main context will be set when initiating the main/parent span.
|
// The main context will be set when initiating the main/parent span.
|
||||||
|
|
||||||
// Create an initial context with the callId param
|
// Create an initial context with the callId param
|
||||||
@ -94,3 +95,4 @@ class CallTracer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const callTracer = new CallTracer();
|
export const callTracer = new CallTracer();
|
||||||
|
*/
|
||||||
|
@ -31,11 +31,12 @@ import { MatrixEvent, IContent } from "matrix-js-sdk/src/models/event";
|
|||||||
import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall";
|
import { GroupCall } from "matrix-js-sdk/src/webrtc/groupCall";
|
||||||
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
|
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
||||||
import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
|
import { CallEvent, VoipEvent } from "matrix-js-sdk/src/webrtc/call";
|
||||||
|
|
||||||
import styles from "./GroupCallInspector.module.css";
|
import styles from "./GroupCallInspector.module.css";
|
||||||
import { SelectInput } from "../input/SelectInput";
|
import { SelectInput } from "../input/SelectInput";
|
||||||
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
||||||
|
import { OTelGroupCallMembership } from "../otel/OTelGroupCallMembership";
|
||||||
|
|
||||||
interface InspectorContextState {
|
interface InspectorContextState {
|
||||||
eventsByUserId?: { [userId: string]: SequenceDiagramMatrixEvent[] };
|
eventsByUserId?: { [userId: string]: SequenceDiagramMatrixEvent[] };
|
||||||
@ -235,7 +236,7 @@ function reducer(
|
|||||||
action: {
|
action: {
|
||||||
type?: CallEvent | ClientEvent | RoomStateEvent;
|
type?: CallEvent | ClientEvent | RoomStateEvent;
|
||||||
event?: MatrixEvent;
|
event?: MatrixEvent;
|
||||||
rawEvent?: Record<string, unknown>;
|
rawEvent?: VoipEvent;
|
||||||
callStateEvent?: MatrixEvent;
|
callStateEvent?: MatrixEvent;
|
||||||
memberStateEvents?: MatrixEvent[];
|
memberStateEvents?: MatrixEvent[];
|
||||||
}
|
}
|
||||||
@ -355,6 +356,18 @@ function useGroupCallState(
|
|||||||
groupCall: GroupCall,
|
groupCall: GroupCall,
|
||||||
showPollCallStats: boolean
|
showPollCallStats: boolean
|
||||||
): InspectorContextState {
|
): InspectorContextState {
|
||||||
|
const [otelMembership] = useState(
|
||||||
|
() => new OTelGroupCallMembership(groupCall)
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
otelMembership.onJoinCall();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
otelMembership.onLeaveCall();
|
||||||
|
};
|
||||||
|
}, [otelMembership]);
|
||||||
|
|
||||||
const [state, dispatch] = useReducer(reducer, {
|
const [state, dispatch] = useReducer(reducer, {
|
||||||
localUserId: client.getUserId(),
|
localUserId: client.getUserId(),
|
||||||
localSessionId: client.getSessionId(),
|
localSessionId: client.getSessionId(),
|
||||||
@ -387,8 +400,10 @@ function useGroupCallState(
|
|||||||
dispatch({ type: ClientEvent.ReceivedVoipEvent, event });
|
dispatch({ type: ClientEvent.ReceivedVoipEvent, event });
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSendVoipEvent(event: Record<string, unknown>) {
|
function onSendVoipEvent(event: VoipEvent) {
|
||||||
dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event });
|
dispatch({ type: CallEvent.SendVoipEvent, rawEvent: event });
|
||||||
|
|
||||||
|
otelMembership.onSendEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUndecryptableToDevice(event: MatrixEvent) {
|
function onUndecryptableToDevice(event: MatrixEvent) {
|
||||||
@ -422,7 +437,7 @@ function useGroupCallState(
|
|||||||
onUndecryptableToDevice
|
onUndecryptableToDevice
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}, [client, groupCall]);
|
}, [client, groupCall, otelMembership]);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ import { useLocationNavigation } from "../useLocationNavigation";
|
|||||||
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
||||||
import { useMediaHandler } from "../settings/useMediaHandler";
|
import { useMediaHandler } from "../settings/useMediaHandler";
|
||||||
import { findDeviceByName, getDevices } from "../media-utils";
|
import { findDeviceByName, getDevices } from "../media-utils";
|
||||||
import { callTracer } from "../telemetry/otel";
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@ -144,7 +143,6 @@ export function GroupCallView({
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
await groupCall.enter();
|
await groupCall.enter();
|
||||||
callTracer.startCall(groupCall.groupCallId);
|
|
||||||
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
||||||
PosthogAnalytics.instance.eventCallStarted.track(groupCall.groupCallId);
|
PosthogAnalytics.instance.eventCallStarted.track(groupCall.groupCallId);
|
||||||
|
|
||||||
@ -165,7 +163,6 @@ export function GroupCallView({
|
|||||||
if (isEmbedded && !preload) {
|
if (isEmbedded && !preload) {
|
||||||
// In embedded mode, bypass the lobby and just enter the call straight away
|
// In embedded mode, bypass the lobby and just enter the call straight away
|
||||||
groupCall.enter();
|
groupCall.enter();
|
||||||
callTracer.startCall(groupCall.groupCallId);
|
|
||||||
|
|
||||||
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
||||||
PosthogAnalytics.instance.eventCallStarted.track(groupCall.groupCallId);
|
PosthogAnalytics.instance.eventCallStarted.track(groupCall.groupCallId);
|
||||||
@ -189,7 +186,6 @@ export function GroupCallView({
|
|||||||
|
|
||||||
// In embedded/widget mode the iFrame will be killed right after the call ended prohibiting the posthog event from getting sent,
|
// In embedded/widget mode the iFrame will be killed right after the call ended prohibiting the posthog event from getting sent,
|
||||||
// therefore we want the event to be sent instantly without getting queued/batched.
|
// therefore we want the event to be sent instantly without getting queued/batched.
|
||||||
callTracer.endCall();
|
|
||||||
const sendInstantly = !!widget;
|
const sendInstantly = !!widget;
|
||||||
PosthogAnalytics.instance.eventCallEnded.track(
|
PosthogAnalytics.instance.eventCallEnded.track(
|
||||||
groupCall.groupCallId,
|
groupCall.groupCallId,
|
||||||
|
@ -32,7 +32,6 @@ import { usePageUnload } from "./usePageUnload";
|
|||||||
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
import { PosthogAnalytics } from "../analytics/PosthogAnalytics";
|
||||||
import { TranslatedError, translatedError } from "../TranslatedError";
|
import { TranslatedError, translatedError } from "../TranslatedError";
|
||||||
import { ElementWidgetActions, ScreenshareStartData, widget } from "../widget";
|
import { ElementWidgetActions, ScreenshareStartData, widget } from "../widget";
|
||||||
import { callTracer } from "../telemetry/otel";
|
|
||||||
|
|
||||||
export enum ConnectionState {
|
export enum ConnectionState {
|
||||||
EstablishingCall = "establishing call", // call hasn't been established yet
|
EstablishingCall = "establishing call", // call hasn't been established yet
|
||||||
@ -376,7 +375,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
|
|||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callTracer.startCall(groupCall.groupCallId);
|
|
||||||
|
|
||||||
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
|
||||||
PosthogAnalytics.instance.eventCallStarted.track(groupCall.groupCallId);
|
PosthogAnalytics.instance.eventCallStarted.track(groupCall.groupCallId);
|
||||||
@ -401,7 +399,6 @@ export function useGroupCall(groupCall: GroupCall): UseGroupCallReturnType {
|
|||||||
const setMicrophoneMuted = useCallback(
|
const setMicrophoneMuted = useCallback(
|
||||||
(setMuted) => {
|
(setMuted) => {
|
||||||
groupCall.setMicrophoneMuted(setMuted);
|
groupCall.setMicrophoneMuted(setMuted);
|
||||||
callTracer.muteMic(setMuted);
|
|
||||||
PosthogAnalytics.instance.eventMuteMicrophone.track(
|
PosthogAnalytics.instance.eventMuteMicrophone.track(
|
||||||
setMuted,
|
setMuted,
|
||||||
groupCall.groupCallId
|
groupCall.groupCallId
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
/* document-load.ts|js file - the code is the same for both the languages */
|
|
||||||
import {
|
|
||||||
ConsoleSpanExporter,
|
|
||||||
SimpleSpanProcessor,
|
|
||||||
} from "@opentelemetry/sdk-trace-base";
|
|
||||||
import { ZipkinExporter } from "@opentelemetry/exporter-zipkin";
|
|
||||||
// import { JaegerExporter } from "@opentelemetry/exporter-jaeger";
|
|
||||||
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
||||||
import { WebTracerProvider } from "@opentelemetry/sdk-trace-web";
|
|
||||||
import { ZoneContextManager } from "@opentelemetry/context-zone";
|
|
||||||
import { registerInstrumentations } from "@opentelemetry/instrumentation";
|
|
||||||
import opentelemetry from "@opentelemetry/api";
|
|
||||||
import { Resource } from "@opentelemetry/resources";
|
|
||||||
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
|
|
||||||
|
|
||||||
import { PosthogSpanExporter } from "../analytics/OtelPosthogExporter";
|
|
||||||
|
|
||||||
const SERVICE_NAME = "element-call";
|
|
||||||
// It is really important to set the correct content type here. Otherwise the Jaeger will crash and not accept the zipkin event
|
|
||||||
// Additionally jaeger needs to be started with zipkin on port 9411
|
|
||||||
const optionsZipkin = {
|
|
||||||
// url: `http://localhost:9411/api/v2/spans`,
|
|
||||||
// serviceName: SERVICE_NAME,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// We DO NOT use the OTLPTraceExporter. This somehow does not hit the right endpoint and also causes issues with CORS
|
|
||||||
const collectorOptions = {
|
|
||||||
// url: `http://localhost:14268/api/v2/spans`, // url is optional and can be omitted - default is http://localhost:4318/v1/traces
|
|
||||||
headers: { "Access-Control-Allow-Origin": "*" }, // an optional object containing custom headers to be sent with each request
|
|
||||||
concurrencyLimit: 10, // an optional limit on pending requests
|
|
||||||
};
|
|
||||||
const otlpExporter = new OTLPTraceExporter(collectorOptions);
|
|
||||||
const consoleExporter = new ConsoleSpanExporter();
|
|
||||||
// The zipkin exporter is the actual exporter we need for web based otel applications
|
|
||||||
const zipkin = new ZipkinExporter(optionsZipkin);
|
|
||||||
const posthogExporter = new PosthogSpanExporter();
|
|
||||||
|
|
||||||
// This is how we can make Jaeger show a reaonsable service in the dropdown on the left.
|
|
||||||
const providerConfig = {
|
|
||||||
resource: new Resource({
|
|
||||||
[SemanticResourceAttributes.SERVICE_NAME]: SERVICE_NAME,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
const provider = new WebTracerProvider(providerConfig);
|
|
||||||
|
|
||||||
provider.addSpanProcessor(new SimpleSpanProcessor(otlpExporter));
|
|
||||||
// We can add as many processors and exporters as we want to. The zipkin one is the important one for Jaeger
|
|
||||||
provider.addSpanProcessor(new SimpleSpanProcessor(posthogExporter));
|
|
||||||
provider.addSpanProcessor(new SimpleSpanProcessor(consoleExporter));
|
|
||||||
provider.addSpanProcessor(new SimpleSpanProcessor(zipkin));
|
|
||||||
|
|
||||||
// This is unecassary i think...
|
|
||||||
provider.register({
|
|
||||||
// Changing default contextManager to use ZoneContextManager - supports asynchronous operations - optional
|
|
||||||
contextManager: new ZoneContextManager(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Registering instrumentations (These are automated span collectors for the Http request during page loading, switching)
|
|
||||||
registerInstrumentations({
|
|
||||||
instrumentations: [
|
|
||||||
// new DocumentLoadInstrumentation(),
|
|
||||||
// new UserInteractionInstrumentation(),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// This is not the serviceName shown in jaeger
|
|
||||||
export const tracer = opentelemetry.trace.getTracer(
|
|
||||||
"my-element-call-otl-tracer"
|
|
||||||
);
|
|
||||||
|
|
||||||
class CallTracer {
|
|
||||||
// We create one tracer class for each main context.
|
|
||||||
// Even if differnt tracer classes overlap in time space, we might want to visulaize them seperately.
|
|
||||||
// The Call Tracer should only contain spans/events that are relevant to understand the procedure of the individual candidates.
|
|
||||||
// Another Tracer Class (for example a ConnectionTracer) can contain a very granular list of all steps to connect to a call.
|
|
||||||
|
|
||||||
private callSpan;
|
|
||||||
private callContext;
|
|
||||||
private muteSpan?;
|
|
||||||
public startCall(callId: string) {
|
|
||||||
// The main context will be set when initiating the main/parent span.
|
|
||||||
|
|
||||||
// Create an initial context with the callId param
|
|
||||||
const callIdContext = opentelemetry.context
|
|
||||||
.active()
|
|
||||||
.setValue(Symbol("callId"), callId);
|
|
||||||
|
|
||||||
// Create the main span that tracks the whole call
|
|
||||||
this.callSpan = tracer.startSpan("otel_callSpan", undefined, callIdContext);
|
|
||||||
|
|
||||||
// Create a new call based on the callIdContext. This context also has a span assigned to it.
|
|
||||||
// Other spans can use this context to extract the parent span.
|
|
||||||
// (When passing this context to startSpan the started span will use the span set in the context (in this case the callSpan) as the parent)
|
|
||||||
this.callContext = opentelemetry.trace.setSpan(
|
|
||||||
opentelemetry.context.active(),
|
|
||||||
this.callSpan
|
|
||||||
);
|
|
||||||
|
|
||||||
// Here we start a very short span. This is a hack to trigger the posthog exporter.
|
|
||||||
// Only ended spans are processed by the exporter.
|
|
||||||
// We want the exporter to know that a call has started
|
|
||||||
const startCallSpan = tracer.startSpan(
|
|
||||||
"otel_startCallSpan",
|
|
||||||
undefined,
|
|
||||||
this.callContext
|
|
||||||
);
|
|
||||||
startCallSpan.end();
|
|
||||||
}
|
|
||||||
public muteMic(muteState: boolean) {
|
|
||||||
if (muteState) {
|
|
||||||
this.muteSpan = tracer.startSpan(
|
|
||||||
"otel_muteSpan",
|
|
||||||
undefined,
|
|
||||||
this.callContext
|
|
||||||
);
|
|
||||||
} else if (this.muteSpan) {
|
|
||||||
this.muteSpan.end();
|
|
||||||
this.muteSpan = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public endCall() {
|
|
||||||
this.callSpan?.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const callTracer = new CallTracer();
|
|
10
yarn.lock
10
yarn.lock
@ -1956,16 +1956,6 @@
|
|||||||
"@opentelemetry/resources" "1.9.1"
|
"@opentelemetry/resources" "1.9.1"
|
||||||
"@opentelemetry/sdk-trace-base" "1.9.1"
|
"@opentelemetry/sdk-trace-base" "1.9.1"
|
||||||
|
|
||||||
"@opentelemetry/exporter-zipkin@^1.9.1":
|
|
||||||
version "1.9.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.9.1.tgz#0bcddf2f3bcb1b26b94a090c953996a28087d21f"
|
|
||||||
integrity sha512-KBgf3w84luP5vWLlrqVFKmbwFK4lXM//t6K7H4nsg576htbz1RpBbQfybADjPdXTjGHqDTtLiC5MC90hxS7Z2w==
|
|
||||||
dependencies:
|
|
||||||
"@opentelemetry/core" "1.9.1"
|
|
||||||
"@opentelemetry/resources" "1.9.1"
|
|
||||||
"@opentelemetry/sdk-trace-base" "1.9.1"
|
|
||||||
"@opentelemetry/semantic-conventions" "1.9.1"
|
|
||||||
|
|
||||||
"@opentelemetry/instrumentation-document-load@^0.31.1":
|
"@opentelemetry/instrumentation-document-load@^0.31.1":
|
||||||
version "0.31.1"
|
version "0.31.1"
|
||||||
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-document-load/-/instrumentation-document-load-0.31.1.tgz#a535a5d1d71706701d3ff560a700b9dd03e4fb59"
|
resolved "https://registry.yarnpkg.com/@opentelemetry/instrumentation-document-load/-/instrumentation-document-load-0.31.1.tgz#a535a5d1d71706701d3ff560a700b9dd03e4fb59"
|
||||||
|
Loading…
Reference in New Issue
Block a user