]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/root-helpers/logger.ts
Translated using Weblate (Icelandic)
[github/Chocobozzz/PeerTube.git] / client / src / root-helpers / logger.ts
1 import { ClientLogCreate } from '@shared/models/server'
2 import { peertubeLocalStorage } from './peertube-web-storage'
3 import { OAuthUserTokens } from './users'
4
5 export type LoggerHook = (message: LoggerMessage, meta?: LoggerMeta) => void
6 export type LoggerLevel = 'info' | 'warn' | 'error'
7
8 export type LoggerMessage = string | Error | object
9 export type LoggerMeta = Error | { [ id: string ]: any, err?: Error }
10
11 declare global {
12 interface Window {
13 logger: Logger
14 }
15 }
16
17 class Logger {
18 private readonly hooks: { level: LoggerLevel, hook: LoggerHook }[] = []
19
20 info (message: LoggerMessage, meta?: LoggerMeta) {
21 this.runHooks('info', message, meta)
22
23 if (meta) console.log(message, meta)
24 else console.log(message)
25 }
26
27 warn (message: LoggerMessage, meta?: LoggerMeta) {
28 this.runHooks('warn', message, meta)
29
30 this.clientWarn(message, meta)
31 }
32
33 clientWarn (message: LoggerMessage, meta?: LoggerMeta) {
34 if (meta) console.warn(message, meta)
35 else console.warn(message)
36 }
37
38 error (message: LoggerMessage, meta?: LoggerMeta) {
39 this.runHooks('error', message, meta)
40
41 this.clientError(message, meta)
42 }
43
44 clientError (message: LoggerMessage, meta?: LoggerMeta) {
45 if (meta) console.error(message, meta)
46 else console.error(message)
47 }
48
49 addHook (level: LoggerLevel, hook: LoggerHook) {
50 this.hooks.push({ level, hook })
51 }
52
53 registerServerSending (serverUrl: string) {
54 this.addHook('warn', (message, meta) => this.sendClientLog(serverUrl, this.buildServerLogPayload('warn', message, meta)))
55 this.addHook('error', (message, meta) => this.sendClientLog(serverUrl, this.buildServerLogPayload('error', message, meta)))
56 }
57
58 sendClientLog (serverUrl: string, payload: ClientLogCreate | null) {
59 if (!payload) return
60
61 const headers = new Headers({
62 'Accept': 'application/json',
63 'Content-Type': 'application/json'
64 })
65
66 try {
67 const tokens = OAuthUserTokens.getUserTokens(peertubeLocalStorage)
68
69 if (tokens) headers.set('Authorization', `${tokens.tokenType} ${tokens.accessToken}`)
70 } catch (err) {
71 console.error('Cannot set tokens to client log sender.', { err })
72 }
73
74 try {
75 fetch(serverUrl + '/api/v1/server/logs/client', {
76 headers,
77 method: 'POST',
78 body: JSON.stringify(payload)
79 })
80 } catch (err) {
81 console.error('Cannot send client warn/error to server.', err)
82 }
83 }
84
85 private buildServerLogPayload (level: Extract<LoggerLevel, 'warn' | 'error'>, message: LoggerMessage, meta?: LoggerMeta) {
86 if (!message) return null
87
88 return {
89 message: this.buildMessageServerLogPayload(message),
90 userAgent: navigator.userAgent,
91 url: window.location.href,
92 level,
93 stackTrace: this.buildStackServerLogPayload(message, meta),
94 meta: this.buildMetaServerLogPayload(meta)
95 }
96 }
97
98 private buildMessageServerLogPayload (message: LoggerMessage) {
99 if (typeof message === 'string') return message
100 if (message instanceof Error) return message.message
101
102 return JSON.stringify(message)
103 }
104
105 private buildStackServerLogPayload (message: LoggerMessage, meta?: LoggerMeta) {
106 if (message instanceof Error) return this.buildStack(message)
107 if (meta instanceof Error) return this.buildStack(meta)
108 if (meta?.err instanceof Error) return this.buildStack(meta.err)
109
110 return undefined
111 }
112
113 private buildMetaServerLogPayload (meta?: LoggerMeta) {
114 if (!meta) return undefined
115 if (meta instanceof Error) return undefined
116
117 let result: string
118
119 try {
120 result = JSON.stringify(meta, (key, value) => {
121 if (key === 'err') return undefined
122
123 return value
124 })
125 } catch (err) {
126 console.error('Cannot stringify meta.', err)
127 }
128
129 return result
130 }
131
132 private runHooks (level: LoggerLevel, message: LoggerMessage, meta?: LoggerMeta) {
133 for (const hookObj of this.hooks) {
134 if (hookObj.level !== level) continue
135
136 hookObj.hook(message, meta)
137 }
138 }
139
140 private buildStack (err: Error) {
141 return `${err.message}\n${err.stack || ''}`
142 }
143 }
144
145 const logger = window.logger || new Logger()
146 window.logger = logger
147
148 export {
149 logger
150 }