Version using events for call joins / leaves and matrix events

This is probably conceptually nicer although isn't quite as nice in
the jaeger / stalk UI.

Also this may no loger work with the posthog exporter (unsure what it
will do with events on spans).
This commit is contained in:
David Baker 2023-03-17 19:26:23 +00:00
parent 2d91b43a7d
commit 63ede0b51a

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import opentelemetry, { Context, Span } from "@opentelemetry/api"; import opentelemetry, { Span, Attributes } from "@opentelemetry/api";
import { import {
GroupCall, GroupCall,
MatrixClient, MatrixClient,
@ -26,20 +26,25 @@ import { VoipEvent } from "matrix-js-sdk/src/webrtc/call";
import { tracer } from "./otel"; import { tracer } from "./otel";
/** /**
* Recursively sets the contents of a todevice event object as attributes on a span * Flattens out an object into a single layer with components
* of the key separated by dots
*/ */
function setNestedAttributesFromEvent(span: Span, event: VoipEvent) { function flattenVoipEvent(event: VoipEvent): Attributes {
setSpanEventAttributesRecursive( const flatObject = {};
span,
flattenVoipEventRecursive(
event as unknown as Record<string, unknown>, // XXX Types event as unknown as Record<string, unknown>, // XXX Types
flatObject,
"matrix.event.", "matrix.event.",
0 0
); );
return flatObject;
} }
function setSpanEventAttributesRecursive( function flattenVoipEventRecursive(
span: Span,
obj: Record<string, unknown>, obj: Record<string, unknown>,
flatObject: Record<string, unknown>,
prefix: string, prefix: string,
depth: number depth: number
) { ) {
@ -50,11 +55,11 @@ function setSpanEventAttributesRecursive(
for (const [k, v] of Object.entries(obj)) { for (const [k, v] of Object.entries(obj)) {
if (["string", "number"].includes(typeof v)) { if (["string", "number"].includes(typeof v)) {
span.setAttribute(prefix + k, v as string | number); flatObject[prefix + k] = v;
} else if (typeof v === "object") { } else if (typeof v === "object") {
setSpanEventAttributesRecursive( flattenVoipEventRecursive(
span,
v as Record<string, unknown>, v as Record<string, unknown>,
flatObject,
prefix + k + ".", prefix + k + ".",
depth + 1 depth + 1
); );
@ -66,7 +71,6 @@ function setSpanEventAttributesRecursive(
* 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
*/ */
export class OTelGroupCallMembership { export class OTelGroupCallMembership {
private context: Context;
private callMembershipSpan: Span; private callMembershipSpan: Span;
private myUserId: string; private myUserId: string;
private myMember: RoomMember; private myMember: RoomMember;
@ -83,7 +87,6 @@ export class OTelGroupCallMembership {
// Create the main span that tracks the time we intend to be in the call // Create the main span that tracks the time we intend to be in the call
this.callMembershipSpan = tracer.startSpan("otel_groupCallMembershipSpan"); this.callMembershipSpan = tracer.startSpan("otel_groupCallMembershipSpan");
this.callMembershipSpan.setAttribute( this.callMembershipSpan.setAttribute(
"matrix.confId", "matrix.confId",
this.groupCall.groupCallId this.groupCall.groupCallId
@ -94,30 +97,16 @@ export class OTelGroupCallMembership {
this.myMember.name this.myMember.name
); );
this.context = opentelemetry.trace.setSpan( opentelemetry.trace.setSpan(
opentelemetry.context.active(), opentelemetry.context.active(),
this.callMembershipSpan this.callMembershipSpan
); );
// Here we start a very short span. This is a hack to trigger the posthog exporter. this.callMembershipSpan.addEvent("matrix.joinCall");
// Only ended spans are processed by the exporter.
// We want the exporter to know that a call has started
const joinCallSpan = tracer.startSpan(
"otel_joinCallSpan",
undefined,
this.context
);
joinCallSpan.end();
} }
public onLeaveCall() { public onLeaveCall() {
// A very short span to represent us leaving the call this.callMembershipSpan.addEvent("matrix.leaveCall");
const startCallSpan = tracer.startSpan(
"otel_leaveCallSpan",
undefined,
this.context
);
startCallSpan.end();
// and end the main span to indicate we've left // and end the main span to indicate we've left
if (this.callMembershipSpan) this.callMembershipSpan.end(); if (this.callMembershipSpan) this.callMembershipSpan.end();
@ -128,17 +117,14 @@ export class OTelGroupCallMembership {
!event || !event ||
(!event.getType().startsWith("m.call") && (!event.getType().startsWith("m.call") &&
!event.getType().startsWith("org.matrix.msc3401.call")) !event.getType().startsWith("org.matrix.msc3401.call"))
) ) {
return; return;
}
const span = tracer.startSpan( this.callMembershipSpan.addEvent(
`otel_onRoomStateEvent_${event.getType()}`, `otel_onRoomStateEvent_${event.getType()}`,
undefined, flattenVoipEvent(event.getContent())
this.context
); );
setNestedAttributesFromEvent(span, event.getContent());
span.end();
} }
public onSendEvent(event: VoipEvent) { public onSendEvent(event: VoipEvent) {
@ -146,23 +132,15 @@ export class OTelGroupCallMembership {
if (!eventType.startsWith("m.call")) return; if (!eventType.startsWith("m.call")) return;
if (event.type === "toDevice") { if (event.type === "toDevice") {
const span = tracer.startSpan( this.callMembershipSpan.addEvent(
`otel_sendToDeviceEvent_${event.eventType}`, `matrix.sendToDeviceEvent_${event.eventType}`,
undefined, flattenVoipEvent(event)
this.context
); );
setNestedAttributesFromEvent(span, event);
span.end();
} else if (event.type === "sendEvent") { } else if (event.type === "sendEvent") {
const span = tracer.startSpan( this.callMembershipSpan.addEvent(
`otel_sendToRoomEvent_${event.eventType}`, `matrix.sendToRoomEvent_${event.eventType}`,
undefined, flattenVoipEvent(event)
this.context
); );
setNestedAttributesFromEvent(span, event);
span.end();
} }
} }
} }