Merge pull request #984 from vector-im/dbkr/otel_peerconn_events
Add OpenTelemetry events for PeerConnection state changes / errors
This commit is contained in:
		
				commit
				
					
						7b88c4330e
					
				
			
		
					 4 changed files with 128 additions and 18 deletions
				
			
		| 
						 | 
					@ -53,7 +53,7 @@
 | 
				
			||||||
    "i18next-browser-languagedetector": "^6.1.8",
 | 
					    "i18next-browser-languagedetector": "^6.1.8",
 | 
				
			||||||
    "i18next-http-backend": "^1.4.4",
 | 
					    "i18next-http-backend": "^1.4.4",
 | 
				
			||||||
    "lodash": "^4.17.21",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
    "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#fe79a6fa7ca50fc7d078e11826b5539bb0822c45",
 | 
					    "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#e89467c9fbf98182def2088a947155f30fdc7d1f",
 | 
				
			||||||
    "matrix-widget-api": "^1.3.1",
 | 
					    "matrix-widget-api": "^1.3.1",
 | 
				
			||||||
    "mermaid": "^8.13.8",
 | 
					    "mermaid": "^8.13.8",
 | 
				
			||||||
    "normalize.css": "^8.0.1",
 | 
					    "normalize.css": "^8.0.1",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										119
									
								
								src/otel/OTelCall.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/otel/OTelCall.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,119 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Span } from "@opentelemetry/api";
 | 
				
			||||||
 | 
					import { MatrixCall } from "matrix-js-sdk";
 | 
				
			||||||
 | 
					import { CallEvent } from "matrix-js-sdk/src/webrtc/call";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { ObjectFlattener } from "./ObjectFlattener";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Tracks an individual call within a group call, either to a full-mesh peer or a focus
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export class OTelCall {
 | 
				
			||||||
 | 
					  constructor(
 | 
				
			||||||
 | 
					    public userId: string,
 | 
				
			||||||
 | 
					    public deviceId: string,
 | 
				
			||||||
 | 
					    public call: MatrixCall,
 | 
				
			||||||
 | 
					    public span: Span
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    if (call.peerConn) {
 | 
				
			||||||
 | 
					      this.addCallPeerConnListeners();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.call.once(
 | 
				
			||||||
 | 
					        CallEvent.PeerConnectionCreated,
 | 
				
			||||||
 | 
					        this.addCallPeerConnListeners
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public dispose() {
 | 
				
			||||||
 | 
					    this.call.peerConn.removeEventListener(
 | 
				
			||||||
 | 
					      "connectionstatechange",
 | 
				
			||||||
 | 
					      this.onCallConnectionStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.removeEventListener(
 | 
				
			||||||
 | 
					      "signalingstatechange",
 | 
				
			||||||
 | 
					      this.onCallSignalingStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.removeEventListener(
 | 
				
			||||||
 | 
					      "iceconnectionstatechange",
 | 
				
			||||||
 | 
					      this.onIceConnectionStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.removeEventListener(
 | 
				
			||||||
 | 
					      "icegatheringstatechange",
 | 
				
			||||||
 | 
					      this.onIceGatheringStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.removeEventListener(
 | 
				
			||||||
 | 
					      "icecandidateerror",
 | 
				
			||||||
 | 
					      this.onIceCandidateError
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private addCallPeerConnListeners = (): void => {
 | 
				
			||||||
 | 
					    this.call.peerConn.addEventListener(
 | 
				
			||||||
 | 
					      "connectionstatechange",
 | 
				
			||||||
 | 
					      this.onCallConnectionStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.addEventListener(
 | 
				
			||||||
 | 
					      "signalingstatechange",
 | 
				
			||||||
 | 
					      this.onCallSignalingStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.addEventListener(
 | 
				
			||||||
 | 
					      "iceconnectionstatechange",
 | 
				
			||||||
 | 
					      this.onIceConnectionStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.addEventListener(
 | 
				
			||||||
 | 
					      "icegatheringstatechange",
 | 
				
			||||||
 | 
					      this.onIceGatheringStateChanged
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    this.call.peerConn.addEventListener(
 | 
				
			||||||
 | 
					      "icecandidateerror",
 | 
				
			||||||
 | 
					      this.onIceCandidateError
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public onCallConnectionStateChanged = (): void => {
 | 
				
			||||||
 | 
					    this.span.addEvent("matrix.call.callConnectionStateChange", {
 | 
				
			||||||
 | 
					      callConnectionState: this.call.peerConn.connectionState,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public onCallSignalingStateChanged = (): void => {
 | 
				
			||||||
 | 
					    this.span.addEvent("matrix.call.callSignalingStateChange", {
 | 
				
			||||||
 | 
					      callSignalingState: this.call.peerConn.signalingState,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public onIceConnectionStateChanged = (): void => {
 | 
				
			||||||
 | 
					    this.span.addEvent("matrix.call.iceConnectionStateChange", {
 | 
				
			||||||
 | 
					      iceConnectionState: this.call.peerConn.iceConnectionState,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public onIceGatheringStateChanged = (): void => {
 | 
				
			||||||
 | 
					    this.span.addEvent("matrix.call.iceGatheringStateChange", {
 | 
				
			||||||
 | 
					      iceGatheringState: this.call.peerConn.iceGatheringState,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public onIceCandidateError = (ev: Event): void => {
 | 
				
			||||||
 | 
					    const flatObject = {};
 | 
				
			||||||
 | 
					    ObjectFlattener.flattenObjectRecursive(ev, flatObject, "error.", 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.span.addEvent("matrix.call.iceCandidateError", flatObject);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@ import { setSpan } from "@opentelemetry/api/build/esm/trace/context-utils";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { ElementCallOpenTelemetry } from "./otel";
 | 
					import { ElementCallOpenTelemetry } from "./otel";
 | 
				
			||||||
import { ObjectFlattener } from "./ObjectFlattener";
 | 
					import { ObjectFlattener } from "./ObjectFlattener";
 | 
				
			||||||
 | 
					import { OTelCall } from "./OTelCall";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Flattens out an object into a single layer with components
 | 
					 * Flattens out an object into a single layer with components
 | 
				
			||||||
| 
						 | 
					@ -86,13 +87,6 @@ function flattenVoipEventRecursive(
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface CallTrackingInfo {
 | 
					 | 
				
			||||||
  userId: string;
 | 
					 | 
				
			||||||
  deviceId: string;
 | 
					 | 
				
			||||||
  call: MatrixCall;
 | 
					 | 
				
			||||||
  span: Span;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 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
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -102,7 +96,7 @@ export class OTelGroupCallMembership {
 | 
				
			||||||
  private myUserId = "unknown";
 | 
					  private myUserId = "unknown";
 | 
				
			||||||
  private myDeviceId: string;
 | 
					  private myDeviceId: string;
 | 
				
			||||||
  private myMember?: RoomMember;
 | 
					  private myMember?: RoomMember;
 | 
				
			||||||
  private callsByCallId = new Map<string, CallTrackingInfo>();
 | 
					  private callsByCallId = new Map<string, OTelCall>();
 | 
				
			||||||
  private statsReportSpan: {
 | 
					  private statsReportSpan: {
 | 
				
			||||||
    span: Span | undefined;
 | 
					    span: Span | undefined;
 | 
				
			||||||
    stats: OTelStatsReportEvent[];
 | 
					    stats: OTelStatsReportEvent[];
 | 
				
			||||||
| 
						 | 
					@ -188,16 +182,13 @@ export class OTelGroupCallMembership {
 | 
				
			||||||
          // XXX: anonymity
 | 
					          // XXX: anonymity
 | 
				
			||||||
          span.setAttribute("matrix.call.target.userId", userId);
 | 
					          span.setAttribute("matrix.call.target.userId", userId);
 | 
				
			||||||
          span.setAttribute("matrix.call.target.deviceId", deviceId);
 | 
					          span.setAttribute("matrix.call.target.deviceId", deviceId);
 | 
				
			||||||
 | 
					 | 
				
			||||||
          const displayName =
 | 
					          const displayName =
 | 
				
			||||||
            this.groupCall.room.getMember(userId)?.name ?? "unknown";
 | 
					            this.groupCall.room.getMember(userId)?.name ?? "unknown";
 | 
				
			||||||
          span.setAttribute("matrix.call.target.displayName", displayName);
 | 
					          span.setAttribute("matrix.call.target.displayName", displayName);
 | 
				
			||||||
          this.callsByCallId.set(call.callId, {
 | 
					          this.callsByCallId.set(
 | 
				
			||||||
            userId,
 | 
					            call.callId,
 | 
				
			||||||
            deviceId,
 | 
					            new OTelCall(userId, deviceId, call, span)
 | 
				
			||||||
            call,
 | 
					          );
 | 
				
			||||||
            span,
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10550,9 +10550,9 @@ matrix-events-sdk@0.0.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd"
 | 
					  resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd"
 | 
				
			||||||
  integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
 | 
					  integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#fe79a6fa7ca50fc7d078e11826b5539bb0822c45":
 | 
					"matrix-js-sdk@github:matrix-org/matrix-js-sdk#e89467c9fbf98182def2088a947155f30fdc7d1f":
 | 
				
			||||||
  version "24.0.0"
 | 
					  version "24.0.0"
 | 
				
			||||||
  resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/fe79a6fa7ca50fc7d078e11826b5539bb0822c45"
 | 
					  resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/e89467c9fbf98182def2088a947155f30fdc7d1f"
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    "@babel/runtime" "^7.12.5"
 | 
					    "@babel/runtime" "^7.12.5"
 | 
				
			||||||
    "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.5"
 | 
					    "@matrix-org/matrix-sdk-crypto-js" "^0.1.0-alpha.5"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue