11import { Resource } from "@opencode-ai/console-resource"
22import type { TraceItem } from "@cloudflare/workers-types"
33
4- type MetricData = Record < string , unknown >
5- type MetricEvent = { time : string ; data : MetricData }
6-
74export default {
85 async tail ( events : TraceItem [ ] ) {
96 for ( const event of events ) {
@@ -24,7 +21,7 @@ export default {
2421 )
2522 continue
2623
27- let data : MetricData = {
24+ let data : Record < string , unknown > = {
2825 "cf.continent" : event . event . request . cf ?. continent ,
2926 "cf.country" : event . event . request . cf ?. country ,
3027 "cf.city" : event . event . request . cf ?. city ,
@@ -38,18 +35,20 @@ export default {
3835 ip : event . event . request . headers [ "x-real-ip" ] ,
3936 }
4037 const time = new Date ( event . eventTimestamp ?? Date . now ( ) ) . toISOString ( )
41- const events : MetricEvent [ ] = [ ]
42- for ( const log of event . logs ) {
43- for ( const message of log . message ) {
44- if ( ! message . startsWith ( "_metric:" ) ) continue
45- const json = JSON . parse ( message . slice ( 8 ) ) as MetricData
46- data = { ...data , ...json }
47- if ( "llm.error.code" in json ) {
48- events . push ( { time, data : { ...data , event_type : "llm.error" } } )
49- }
50- }
51- }
52- events . push ( { time, data : { ...data , event_type : "completions" } } )
38+ const events = [
39+ ...event . logs . flatMap ( ( log ) =>
40+ log . message . flatMap ( ( message : string ) => {
41+ if ( ! message . startsWith ( "_metric:" ) ) return [ ]
42+ const json = JSON . parse ( message . slice ( 8 ) ) as Record < string , unknown >
43+ data = { ...data , ...json }
44+ if ( "llm.error.code" in json ) {
45+ return [ { time, data : { ...data , event_type : "llm.error" } } ]
46+ }
47+ return [ ]
48+ } ) ,
49+ ) ,
50+ { time, data : { ...data , event_type : "completions" } } ,
51+ ]
5352 console . log ( JSON . stringify ( data , null , 2 ) )
5453
5554 const [ honeycomb , lake ] = await Promise . all ( [
@@ -78,7 +77,7 @@ export default {
7877 } ,
7978}
8079
81- function toLakeEvent ( time : string , data : MetricData ) {
80+ function toLakeEvent ( time : string , data : Record < string , unknown > ) {
8281 const tokensInput = integer ( data , "tokens.input" )
8382 const tokensOutput = integer ( data , "tokens.output" )
8483 const tokensReasoning = integer ( data , "tokens.reasoning" )
@@ -90,16 +89,14 @@ function toLakeEvent(time: string, data: MetricData) {
9089 const source = string ( data , "source" )
9190
9291 return {
93- _lake_database : Resource . InferenceEventLake . database ,
94- _lake_table : Resource . InferenceEventLake . table ,
95- _lake_operation : "insert" ,
92+ type : "inference.event" ,
9693 event_timestamp : time ,
9794 event_date : time . slice ( 0 , 10 ) ,
9895 event_type : string ( data , "event_type" ) ,
9996 dataset : "zen" ,
10097 client : string ( data , "client" ) ,
10198 source,
102- tier : tier ( source ) ,
99+ tier : source ,
103100 provider : string ( data , "provider" ) ,
104101 provider_model : string ( data , "provider.model" ) ,
105102 model : string ( data , "model" ) ,
@@ -145,40 +142,32 @@ function toLakeEvent(time: string, data: MetricData) {
145142 }
146143}
147144
148- function tier ( source : string | undefined ) {
149- if ( source === "anonymous" || source === "free" ) return "Free"
150- if ( source === "lite" ) return "Go"
151- if ( source === "subscription" || source === "balance" ) return "Zen"
152- if ( source === "byok" ) return "BYOK"
153- return undefined
154- }
155-
156145function outputTps ( tokens : number | undefined , firstByte : number | undefined , lastByte : number | undefined ) {
157146 if ( ! tokens || ! firstByte || ! lastByte || lastByte <= firstByte ) return undefined
158147 return Number ( ( ( tokens / ( lastByte - firstByte ) ) * 1000 ) . toFixed ( 6 ) )
159148}
160149
161- function string ( data : MetricData , key : string ) {
150+ function string ( data : Record < string , unknown > , key : string ) {
162151 const value = data [ key ]
163152 if ( typeof value === "string" ) return value
164153 if ( typeof value === "number" || typeof value === "boolean" ) return String ( value )
165154 return undefined
166155}
167156
168- function boolean ( data : MetricData , key : string ) {
157+ function boolean ( data : Record < string , unknown > , key : string ) {
169158 const value = data [ key ]
170159 if ( typeof value === "boolean" ) return value
171160 if ( typeof value === "string" ) return value === "true" ? true : value === "false" ? false : undefined
172161 return undefined
173162}
174163
175- function integer ( data : MetricData , key : string ) {
164+ function integer ( data : Record < string , unknown > , key : string ) {
176165 const value = number ( data , key )
177166 if ( value === undefined ) return undefined
178167 return Math . round ( value )
179168}
180169
181- function number ( data : MetricData , key : string ) {
170+ function number ( data : Record < string , unknown > , key : string ) {
182171 const value = data [ key ]
183172 if ( typeof value === "number" ) return Number . isFinite ( value ) ? value : undefined
184173 if ( typeof value === "string" ) {
0 commit comments