chatgpt-api/src/logging.ts

143 wiersze
3.8 KiB
TypeScript
Czysty Zwykły widok Historia

import logger from 'debug'
import { v4 as uuidv4 } from 'uuid'
/**
2023-06-04 16:36:54 +00:00
* List of events that can occur within the library.
*/
2023-06-04 16:36:54 +00:00
export const Events = {
LLM_CALL: 'LLM_CALL',
LLM_COMPLETION: 'LLM_COMPLETION'
} as const
export type EventType = (typeof Events)[keyof typeof Events]
/**
* Severity levels of an event.
*/
2023-06-04 16:36:54 +00:00
export const Severity = {
DEBUG: 0,
INFO: 1,
WARNING: 2,
ERROR: 3,
CRITICAL: 4
} as const
type SeverityType = (typeof Severity)[keyof typeof Severity]
/*
2023-06-04 16:36:54 +00:00
* Define minimum LOG_LEVEL, defaulting to Severity.INFO if not provided or if an invalid value is provided. Any events below that level won't be logged to the console.
*/
2023-06-04 16:36:54 +00:00
let LOG_LEVEL: SeverityType = Severity.INFO
2023-06-11 00:50:52 +00:00
if (
process.env.DEBUG_LOG_LEVEL &&
2023-06-04 16:36:54 +00:00
Severity[process.env.DEBUG_LOG_LEVEL.toUpperCase()] !== undefined
) {
2023-06-04 16:36:54 +00:00
LOG_LEVEL = Severity[process.env.DEBUG_LOG_LEVEL.toUpperCase()]
} else if (process.env.DEBUG_LOG_LEVEL) {
throw new Error(`Invalid value for LOG_LEVEL: ${process.env.DEBUG_LOG_LEVEL}`)
}
/**
* Define loggers for each severity level such that logs can be filtered by severity.
*/
2023-06-04 16:36:54 +00:00
const LOGGERS: Record<SeverityType, ReturnType<typeof logger>> = {
[Severity.CRITICAL]: logger('agentic:events:critical'),
[Severity.ERROR]: logger('agentic:events:error'),
[Severity.WARNING]: logger('agentic:events:warning'),
[Severity.INFO]: logger('agentic:events:info'),
[Severity.DEBUG]: logger('agentic:events:debug')
}
/**
* Payload of an event.
*/
interface EventPayload {
[key: string]: unknown
}
/**
* Data required to create a new Event object.
*/
interface EventData {
parentId?: string
id?: string
timestamp?: Date
payload?: EventPayload
2023-06-04 16:36:54 +00:00
severity?: SeverityType
version?: number
}
/**
* Events that occur within the library (should be treated as immutable).
*/
export class Event {
public readonly type: EventType
public readonly parentId?: string
public readonly id: string
public readonly timestamp: Date
public readonly payload?: EventPayload
2023-06-04 16:36:54 +00:00
public readonly severity: SeverityType
public readonly version: number
constructor(type: EventType, data: EventData = {}) {
this.type = type
2023-06-04 16:36:54 +00:00
this.parentId = data.parentId
this.id = data.id ?? uuidv4()
this.timestamp = data.timestamp ?? new Date()
this.payload = data.payload ? { ...data.payload } : {} // Only doing a shallow instead of a deep copy for performance reasons..
2023-06-04 16:36:54 +00:00
this.severity = data.severity ?? Severity.INFO
this.version = data.version ?? 1 // Default to version 1 if not provided...
}
/**
* Converts a JSON string representation of an event back into an Event object.
*/
static fromJSON(json: string): Event {
const { type, ...data } = JSON.parse(json)
// Convert the timestamp back into a Date object, since `JSON.parse()` will have turned it into a string:
data.timestamp = new Date(data.timestamp)
const event = new Event(type, data)
return event
}
/**
* Converts the event to a JSON string representation.
*
* @returns JSON representation
*/
toJSON(): string {
return JSON.stringify({
type: this.type,
parentId: this.parentId,
id: this.id,
timestamp: this.timestamp.toISOString(),
payload: this.payload,
severity: this.severity,
version: this.version
})
}
/**
* Converts the event to a human-readable string representation suitable for logging.
*
* @returns string representation
*/
toString(): string {
return `Event { type: ${this.type}, parentId: ${this.parentId}, id: ${
this.id
}, timestamp: ${this.timestamp.toISOString()}, payload: ${JSON.stringify(
this.payload
)}, severity: ${this.severity} }`
}
/**
* Logs the event to the console.
*/
log(): void {
if (this.severity >= LOG_LEVEL) {
const logger = LOGGERS[this.severity]
logger(this.toString())
}
}
}