Version that does at least send some traces
This commit is contained in:
		
					parent
					
						
							
								1e2cd97764
							
						
					
				
			
			
				commit
				
					
						c519e13885
					
				
			
		
					 8 changed files with 73 additions and 278 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (event.type === "toDevice") {
 | 
				
			||||||
      const span = tracer.startSpan(
 | 
					      const span = tracer.startSpan(
 | 
				
			||||||
      `otel_sendToDeviceEvent_${toDeviceEvent.eventType}`,
 | 
					        `otel_sendToDeviceEvent_${event.eventType}`,
 | 
				
			||||||
        undefined,
 | 
					        undefined,
 | 
				
			||||||
        this.context
 | 
					        this.context
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const [k, v] of Object.entries(toDeviceEvent)) {
 | 
					      setNestedAttributesFromToDeviceEvent(span, event);
 | 
				
			||||||
      if (["string", "number"].includes(typeof v))
 | 
					 | 
				
			||||||
        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();
 | 
					      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…
	
	Add table
		Add a link
		
	
		Reference in a new issue