151 lines
4.1 KiB
TypeScript
151 lines
4.1 KiB
TypeScript
import { ClientLogCreate } from '@peertube/peertube-models'
|
|
import { peertubeLocalStorage } from './peertube-web-storage'
|
|
import { OAuthUserTokens } from './users'
|
|
|
|
export type LoggerHook = (message: LoggerMessage, meta?: LoggerMeta) => void
|
|
export type LoggerLevel = 'info' | 'warn' | 'error'
|
|
|
|
export type LoggerMessage = string | Error | object
|
|
export type LoggerMeta = Error | { [ id: string ]: any, err?: Error }
|
|
|
|
declare global {
|
|
interface Window {
|
|
logger: Logger
|
|
}
|
|
}
|
|
|
|
class Logger {
|
|
private readonly hooks: { level: LoggerLevel, hook: LoggerHook }[] = []
|
|
|
|
info (message: LoggerMessage, meta?: LoggerMeta) {
|
|
this.runHooks('info', message, meta)
|
|
|
|
if (meta) console.log(message, meta)
|
|
else console.log(message)
|
|
}
|
|
|
|
warn (message: LoggerMessage, meta?: LoggerMeta) {
|
|
this.runHooks('warn', message, meta)
|
|
|
|
this.clientWarn(message, meta)
|
|
}
|
|
|
|
clientWarn (message: LoggerMessage, meta?: LoggerMeta) {
|
|
if (meta) console.warn(message, meta)
|
|
else console.warn(message)
|
|
}
|
|
|
|
error (message: LoggerMessage, meta?: LoggerMeta) {
|
|
this.runHooks('error', message, meta)
|
|
|
|
this.clientError(message, meta)
|
|
}
|
|
|
|
clientError (message: LoggerMessage, meta?: LoggerMeta) {
|
|
if (meta) console.error(message, meta)
|
|
else console.error(message)
|
|
}
|
|
|
|
addHook (level: LoggerLevel, hook: LoggerHook) {
|
|
this.hooks.push({ level, hook })
|
|
}
|
|
|
|
registerServerSending (serverUrl: string) {
|
|
this.addHook('warn', (message, meta) => this.sendClientLog(serverUrl, this.buildServerLogPayload('warn', message, meta)))
|
|
this.addHook('error', (message, meta) => this.sendClientLog(serverUrl, this.buildServerLogPayload('error', message, meta)))
|
|
}
|
|
|
|
sendClientLog (serverUrl: string, payload: ClientLogCreate | null) {
|
|
if (!payload) return
|
|
|
|
const headers = new Headers({
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json'
|
|
})
|
|
|
|
try {
|
|
const tokens = OAuthUserTokens.getUserTokens(peertubeLocalStorage)
|
|
|
|
if (tokens) headers.set('Authorization', `${tokens.tokenType} ${tokens.accessToken}`)
|
|
} catch (err) {
|
|
console.error('Cannot set tokens to client log sender.', { err })
|
|
}
|
|
|
|
try {
|
|
fetch(serverUrl + '/api/v1/server/logs/client', {
|
|
headers,
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
})
|
|
} catch (err) {
|
|
console.error('Cannot send client warn/error to server.', err)
|
|
}
|
|
}
|
|
|
|
private buildServerLogPayload (level: Extract<LoggerLevel, 'warn' | 'error'>, message: LoggerMessage, meta?: LoggerMeta) {
|
|
if (!message) return null
|
|
|
|
return {
|
|
message: this.buildMessageServerLogPayload(message),
|
|
userAgent: navigator.userAgent,
|
|
url: window.location.href,
|
|
level,
|
|
stackTrace: this.buildStackServerLogPayload(message, meta),
|
|
meta: this.buildMetaServerLogPayload(meta)
|
|
}
|
|
}
|
|
|
|
private buildMessageServerLogPayload (message: LoggerMessage) {
|
|
if (typeof message === 'string') return message
|
|
if (message instanceof Error) return message.message
|
|
|
|
return JSON.stringify(message)
|
|
}
|
|
|
|
private buildStackServerLogPayload (message: LoggerMessage, meta?: LoggerMeta) {
|
|
if (message instanceof Error) return this.buildStack(message)
|
|
if (meta instanceof Error) return this.buildStack(meta)
|
|
if (meta?.err instanceof Error) return this.buildStack(meta.err)
|
|
|
|
return undefined
|
|
}
|
|
|
|
private buildMetaServerLogPayload (meta?: LoggerMeta) {
|
|
if (!meta) return undefined
|
|
if (meta instanceof Error) return undefined
|
|
|
|
let result: string
|
|
|
|
try {
|
|
result = JSON.stringify(meta, (key, value) => {
|
|
if (key === 'err') return undefined
|
|
|
|
return value
|
|
})
|
|
} catch (err) {
|
|
console.error('Cannot stringify meta.', err)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
private runHooks (level: LoggerLevel, message: LoggerMessage, meta?: LoggerMeta) {
|
|
for (const hookObj of this.hooks) {
|
|
if (hookObj.level !== level) continue
|
|
|
|
hookObj.hook(message, meta)
|
|
}
|
|
}
|
|
|
|
private buildStack (err: Error) {
|
|
return `${err.message}\n${err.stack || ''}`
|
|
}
|
|
}
|
|
|
|
const logger = window.logger || new Logger()
|
|
window.logger = logger
|
|
|
|
export {
|
|
logger
|
|
}
|