@@ -17,19 +17,8 @@ export class MetricsTracker {
1717
1818 logEvent ( event : MetricsEvent ) : void {
1919 try {
20+ event . serverInfo = this . mcpServerInfo
2021 let dataPoint = event . toDataPoint ( )
21- if (
22- dataPoint . blobs &&
23- dataPoint . blobs . length >= 2 &&
24- dataPoint . blobs [ 0 ] === null &&
25- dataPoint . blobs [ 1 ] === null
26- ) {
27- dataPoint . blobs [ 0 ] = this . mcpServerInfo . name
28- dataPoint . blobs [ 1 ] = this . mcpServerInfo . version
29- } else {
30- // we should never hit this because of type definitions and our mapBlobs utility function
31- throw new MetricsError ( 'Unexpected result from toDataPoint, could not add MCP server info. Was the `mapBlobs` utility function used?' )
32- }
3322 this . wae . writeDataPoint ( dataPoint )
3423 } catch ( e ) {
3524 console . error ( `Failed to log metrics event, ${ e } ` )
@@ -43,13 +32,77 @@ export class MetricsTracker {
4332 * Each event type is stored with a different indexId and has an associated class which
4433 * maps a more ergonomic event object to a ReadyAnalyticsEvent
4534 */
46- export interface MetricsEvent {
35+ export abstract class MetricsEvent {
36+ public _serverInfo : { name : string , version : string } | undefined
37+ set serverInfo ( serverInfo : { name : string , version : string } ) {
38+ this . _serverInfo = serverInfo
39+ }
40+
41+ get serverInfo ( ) : { name : string , version : string } {
42+ if ( ! this . _serverInfo ) {
43+ throw new Error ( "Server info not set" )
44+ }
45+ return this . _serverInfo
46+ }
47+
4748 /**
4849 * Output a valid AnalyticsEngineDataPoint. Use `mapBlobs` and `mapDoubles` to write well defined
4950 * analytics engine datapoints. The first and second blob entries are reserved for the MCP server name and
5051 * MCP server version.
5152 */
52- toDataPoint ( ) : AnalyticsEngineDataPoint
53+ abstract toDataPoint ( ) : AnalyticsEngineDataPoint
54+
55+ mapBlobs ( blobs : Blobs ) : Array < string | null > {
56+ if ( blobs . blob1 || blobs . blob2 ) {
57+ throw new MetricsError ( 'Failed to map blobs, blob1 and blob2 are reserved for MCP server info' )
58+ }
59+ // add placeholder blobs, filled in by the MetricsTracker later
60+ blobs . blob1 = this . serverInfo . name
61+ blobs . blob2 = this . serverInfo . version
62+ const blobsArray = new Array ( Object . keys ( blobs ) . length )
63+ for ( const [ key , value ] of Object . entries ( blobs ) ) {
64+ const match = key . match ( / ^ b l o b ( \d + ) $ / )
65+ if ( match === null || match . length < 2 ) {
66+ // we should never hit this because of the typedefinitions above,
67+ // but this error is for safety
68+ throw new MetricsError ( 'Failed to map blobs, invalid key' )
69+ }
70+ const index = parseInt ( match [ 1 ] , 10 )
71+ if ( isNaN ( index ) ) {
72+ // we should never hit this because of the typedefinitions above,
73+ // but this esrror is for safety
74+ throw new MetricsError ( 'Failed to map blobs, invalid index' )
75+ }
76+ if ( index - 1 >= blobsArray . length ) {
77+ throw new MetricsError ( 'Failed to map blobs, missing blob' )
78+ }
79+ blobsArray [ index - 1 ] = value
80+ }
81+ return blobsArray
82+ }
83+
84+ mapDoubles ( doubles : Doubles ) : number [ ] {
85+ const doublesArray = new Array ( Object . keys ( doubles ) . length )
86+ for ( const [ key , value ] of Object . entries ( doubles ) ) {
87+ const match = key . match ( / ^ d o u b l e ( \d + ) $ / )
88+ if ( match === null || match . length < 2 ) {
89+ // we should never hit this because of the typedefinitions above,
90+ // but this error is for safety
91+ throw new MetricsError ( ': Failed to map doubles, invalid key' )
92+ }
93+ const index = parseInt ( match [ 1 ] , 10 )
94+ if ( isNaN ( index ) ) {
95+ // we should never hit this because of the typedefinitions above,
96+ // but this error is for safety
97+ throw new MetricsError ( 'Failed to map doubles, invalid index' )
98+ }
99+ if ( index - 1 >= doublesArray . length ) {
100+ throw new MetricsError ( 'Failed to map doubles, missing blob' )
101+ }
102+ doublesArray [ index - 1 ] = value
103+ }
104+ return doublesArray
105+ }
53106}
54107
55108export enum MetricsEventIndexIds {
@@ -92,7 +145,7 @@ type Range1To20 =
92145// blob1 and blob2 are reserved for server name and version
93146type Blobs = {
94147 [ key in `blob${Range1To20 } `] ?: string | null
95- } & { blob1 ?: never ; blob2 ?: never }
148+ }
96149
97150type Doubles = {
98151 [ key in `double${Range1To20 } `] ?: number
@@ -103,69 +156,4 @@ export class MetricsError extends Error {
103156 super ( message )
104157 this . name = 'MetricsError'
105158 }
106- }
107-
108- /**
109- *
110- * @param blobs Named blobs to map to an array. blob1 and blob2 are reserved.
111- * @returns Array of blobs
112- */
113- export function mapBlobs ( blobs : Blobs ) : Array < string | null > {
114- if ( blobs . blob1 || blobs . blob2 ) {
115- throw new MetricsError ( 'Failed to map blobs, blob1 and blob2 are reserved for MCP server info' )
116- }
117- // add placeholder blobs, filled in by the MetricsTracker later
118- blobs = {
119- ...blobs ,
120- blob1 : undefined ,
121- blob2 : undefined
122- }
123- const blobsArray = new Array ( Object . keys ( blobs ) . length )
124- for ( const [ key , value ] of Object . entries ( blobs ) ) {
125- const match = key . match ( / ^ b l o b ( \d + ) $ / )
126- if ( match === null || match . length < 2 ) {
127- // we should never hit this because of the typedefinitions above,
128- // but this error is for safety
129- throw new MetricsError ( 'Failed to map blobs, invalid key' )
130- }
131- const index = parseInt ( match [ 1 ] , 10 )
132- if ( isNaN ( index ) ) {
133- // we should never hit this because of the typedefinitions above,
134- // but this error is for safety
135- throw new MetricsError ( 'Failed to map blobs, invalid index' )
136- }
137- if ( index - 1 >= blobsArray . length ) {
138- throw new MetricsError ( 'Failed to map blobs, missing blob' )
139- }
140- blobsArray [ index - 1 ] = value
141- }
142- return blobsArray
143- }
144-
145- /**
146- *
147- * @param doubles List of named doubles
148- * @returns Doubles mapped to a valid WAE doubles array
149- */
150- export function mapDoubles ( doubles : Doubles ) : number [ ] {
151- const doublesArray = new Array ( Object . keys ( doubles ) . length )
152- for ( const [ key , value ] of Object . entries ( doubles ) ) {
153- const match = key . match ( / ^ d o u b l e ( \d + ) $ / )
154- if ( match === null || match . length < 2 ) {
155- // we should never hit this because of the typedefinitions above,
156- // but this error is for safety
157- throw new MetricsError ( ': Failed to map doubles, invalid key' )
158- }
159- const index = parseInt ( match [ 1 ] , 10 )
160- if ( isNaN ( index ) ) {
161- // we should never hit this because of the typedefinitions above,
162- // but this error is for safety
163- throw new MetricsError ( 'Failed to map doubles, invalid index' )
164- }
165- if ( index - 1 >= doublesArray . length ) {
166- throw new MetricsError ( 'Failed to map doubles, missing blob' )
167- }
168- doublesArray [ index - 1 ] = value
169- }
170- return doublesArray
171- }
159+ }
0 commit comments