2023-03-15 14:35:10 +00:00
|
|
|
/*
|
|
|
|
|
Copyright 2023 New Vector Ltd
|
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
|
limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
2023-03-17 19:26:23 +00:00
|
|
|
import opentelemetry, { Span, Attributes } from "@opentelemetry/api";
|
2023-03-17 17:01:59 +00:00
|
|
|
import {
|
|
|
|
|
GroupCall,
|
|
|
|
|
MatrixClient,
|
|
|
|
|
MatrixEvent,
|
|
|
|
|
RoomMember,
|
|
|
|
|
} from "matrix-js-sdk";
|
2023-03-15 16:00:39 +00:00
|
|
|
import { VoipEvent } from "matrix-js-sdk/src/webrtc/call";
|
2023-03-15 14:35:10 +00:00
|
|
|
|
|
|
|
|
import { tracer } from "./otel";
|
|
|
|
|
|
2023-03-15 16:00:39 +00:00
|
|
|
/**
|
2023-03-17 19:26:23 +00:00
|
|
|
* Flattens out an object into a single layer with components
|
|
|
|
|
* of the key separated by dots
|
2023-03-15 16:00:39 +00:00
|
|
|
*/
|
2023-03-17 19:26:23 +00:00
|
|
|
function flattenVoipEvent(event: VoipEvent): Attributes {
|
|
|
|
|
const flatObject = {};
|
|
|
|
|
|
|
|
|
|
flattenVoipEventRecursive(
|
2023-03-15 16:00:39 +00:00
|
|
|
event as unknown as Record<string, unknown>, // XXX Types
|
2023-03-17 19:26:23 +00:00
|
|
|
flatObject,
|
2023-03-16 14:41:55 +00:00
|
|
|
"matrix.event.",
|
2023-03-15 16:00:39 +00:00
|
|
|
0
|
|
|
|
|
);
|
2023-03-17 19:26:23 +00:00
|
|
|
|
|
|
|
|
return flatObject;
|
2023-03-15 16:00:39 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-17 19:26:23 +00:00
|
|
|
function flattenVoipEventRecursive(
|
2023-03-15 16:00:39 +00:00
|
|
|
obj: Record<string, unknown>,
|
2023-03-17 19:26:23 +00:00
|
|
|
flatObject: Record<string, unknown>,
|
2023-03-15 16:00:39 +00:00
|
|
|
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)) {
|
2023-03-17 19:26:23 +00:00
|
|
|
flatObject[prefix + k] = v;
|
2023-03-15 16:00:39 +00:00
|
|
|
} else if (typeof v === "object") {
|
2023-03-17 19:26:23 +00:00
|
|
|
flattenVoipEventRecursive(
|
2023-03-15 16:00:39 +00:00
|
|
|
v as Record<string, unknown>,
|
2023-03-17 19:26:23 +00:00
|
|
|
flatObject,
|
2023-03-15 16:00:39 +00:00
|
|
|
prefix + k + ".",
|
|
|
|
|
depth + 1
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-15 14:35:10 +00:00
|
|
|
/**
|
|
|
|
|
* Represent the span of time which we intend to be joined to a group call
|
|
|
|
|
*/
|
|
|
|
|
export class OTelGroupCallMembership {
|
|
|
|
|
private callMembershipSpan: Span;
|
2023-03-17 17:01:59 +00:00
|
|
|
private myUserId: string;
|
|
|
|
|
private myMember: RoomMember;
|
2023-03-15 14:35:10 +00:00
|
|
|
|
2023-03-17 17:01:59 +00:00
|
|
|
constructor(private groupCall: GroupCall, client: MatrixClient) {
|
|
|
|
|
this.myUserId = client.getUserId();
|
|
|
|
|
this.myMember = groupCall.room.getMember(client.getUserId());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onJoinCall() {
|
2023-03-16 14:41:55 +00:00
|
|
|
// 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)
|
2023-03-15 14:35:10 +00:00
|
|
|
|
2023-03-17 17:01:59 +00:00
|
|
|
// Create the main span that tracks the time we intend to be in the call
|
|
|
|
|
this.callMembershipSpan = tracer.startSpan("otel_groupCallMembershipSpan");
|
2023-03-17 19:03:43 +00:00
|
|
|
this.callMembershipSpan.setAttribute(
|
|
|
|
|
"matrix.confId",
|
|
|
|
|
this.groupCall.groupCallId
|
|
|
|
|
);
|
|
|
|
|
this.callMembershipSpan.setAttribute("matrix.userId", this.myUserId);
|
|
|
|
|
this.callMembershipSpan.setAttribute(
|
|
|
|
|
"matrix.displayName",
|
|
|
|
|
this.myMember.name
|
|
|
|
|
);
|
|
|
|
|
|
2023-03-17 19:26:23 +00:00
|
|
|
opentelemetry.trace.setSpan(
|
2023-03-17 19:03:43 +00:00
|
|
|
opentelemetry.context.active(),
|
|
|
|
|
this.callMembershipSpan
|
|
|
|
|
);
|
2023-03-15 14:35:10 +00:00
|
|
|
|
2023-03-17 19:26:23 +00:00
|
|
|
this.callMembershipSpan.addEvent("matrix.joinCall");
|
2023-03-15 14:35:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public onLeaveCall() {
|
2023-03-17 19:26:23 +00:00
|
|
|
this.callMembershipSpan.addEvent("matrix.leaveCall");
|
2023-03-15 14:35:10 +00:00
|
|
|
|
|
|
|
|
// and end the main span to indicate we've left
|
2023-03-16 14:41:55 +00:00
|
|
|
if (this.callMembershipSpan) this.callMembershipSpan.end();
|
2023-03-15 14:35:10 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-16 18:08:28 +00:00
|
|
|
public onUpdateRoomState(event: MatrixEvent) {
|
|
|
|
|
if (
|
|
|
|
|
!event ||
|
|
|
|
|
(!event.getType().startsWith("m.call") &&
|
|
|
|
|
!event.getType().startsWith("org.matrix.msc3401.call"))
|
2023-03-17 19:26:23 +00:00
|
|
|
) {
|
2023-03-16 18:08:28 +00:00
|
|
|
return;
|
2023-03-17 19:26:23 +00:00
|
|
|
}
|
2023-03-16 18:08:28 +00:00
|
|
|
|
2023-03-17 19:26:23 +00:00
|
|
|
this.callMembershipSpan.addEvent(
|
2023-03-16 18:08:28 +00:00
|
|
|
`otel_onRoomStateEvent_${event.getType()}`,
|
2023-03-17 19:26:23 +00:00
|
|
|
flattenVoipEvent(event.getContent())
|
2023-03-16 18:08:28 +00:00
|
|
|
);
|
|
|
|
|
}
|
2023-03-15 14:35:10 +00:00
|
|
|
|
2023-03-15 16:00:39 +00:00
|
|
|
public onSendEvent(event: VoipEvent) {
|
|
|
|
|
const eventType = event.eventType as string;
|
2023-03-15 14:35:10 +00:00
|
|
|
if (!eventType.startsWith("m.call")) return;
|
|
|
|
|
|
2023-03-15 16:00:39 +00:00
|
|
|
if (event.type === "toDevice") {
|
2023-03-17 19:26:23 +00:00
|
|
|
this.callMembershipSpan.addEvent(
|
|
|
|
|
`matrix.sendToDeviceEvent_${event.eventType}`,
|
|
|
|
|
flattenVoipEvent(event)
|
2023-03-15 16:00:39 +00:00
|
|
|
);
|
2023-03-16 18:08:28 +00:00
|
|
|
} else if (event.type === "sendEvent") {
|
2023-03-17 19:26:23 +00:00
|
|
|
this.callMembershipSpan.addEvent(
|
|
|
|
|
`matrix.sendToRoomEvent_${event.eventType}`,
|
|
|
|
|
flattenVoipEvent(event)
|
2023-03-16 18:08:28 +00:00
|
|
|
);
|
2023-03-15 14:35:10 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|