-// Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/
import { stat } from 'fs-extra'
-import { omit } from 'lodash'
import { join } from 'path'
import { format as sqlFormat } from 'sql-formatter'
import { createLogger, format, transports } from 'winston'
import { FileTransportOptions } from 'winston/lib/winston/transports'
+import { context } from '@opentelemetry/api'
+import { getSpanContext } from '@opentelemetry/api/build/src/trace/context-utils'
+import { omit } from '@shared/core-utils'
import { CONFIG } from '../initializers/config'
import { LOG_FILENAME } from '../initializers/constants'
const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT
-function getLoggerReplacer () {
- const seen = new WeakSet()
-
- // Thanks: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#Examples
- return (key: string, value: any) => {
- if (key === 'cert') return 'Replaced by the logger to avoid large log message'
-
- if (typeof value === 'object' && value !== null) {
- if (seen.has(value)) return
-
- seen.add(value)
- }
-
- if (value instanceof Set) {
- return Array.from(value)
- }
-
- if (value instanceof Map) {
- return Array.from(value.entries())
- }
-
- if (value instanceof Error) {
- const error = {}
-
- Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] })
-
- return error
- }
-
- return value
- }
-}
-
const consoleLoggerFormat = format.printf(info => {
- const toOmit = [ 'label', 'timestamp', 'level', 'message', 'sql', 'tags' ]
-
- const obj = omit(info, ...toOmit)
-
- let additionalInfos = JSON.stringify(obj, getLoggerReplacer(), 2)
+ let additionalInfos = JSON.stringify(getAdditionalInfo(info), removeCyclicValues(), 2)
if (additionalInfos === undefined || additionalInfos === '{}') additionalInfos = ''
else additionalInfos = ' ' + additionalInfos
})
const jsonLoggerFormat = format.printf(info => {
- return JSON.stringify(info, getLoggerReplacer())
+ return JSON.stringify(info, removeCyclicValues())
})
const timestampFormatter = format.timestamp({
fileLoggerOptions.maxFiles = CONFIG.LOG.ROTATION.MAX_FILES
}
-const logger = buildLogger()
-
function buildLogger (labelSuffix?: string) {
return createLogger({
level: CONFIG.LOG.LEVEL,
+ defaultMeta: {
+ get traceId () { return getSpanContext(context.active())?.traceId },
+ get spanId () { return getSpanContext(context.active())?.spanId },
+ get traceFlags () { return getSpanContext(context.active())?.traceFlags }
+ },
format: format.combine(
labelFormatter(labelSuffix),
format.splat()
})
}
+const logger = buildLogger()
+
+// ---------------------------------------------------------------------------
+
function bunyanLogFactory (level: string) {
return function (...params: any[]) {
let meta = null
level: () => { },
trace: bunyanLogFactory('debug'),
debug: bunyanLogFactory('debug'),
+ verbose: bunyanLogFactory('debug'),
info: bunyanLogFactory('info'),
warn: bunyanLogFactory('warn'),
error: bunyanLogFactory('error'),
fatal: bunyanLogFactory('error')
}
+// ---------------------------------------------------------------------------
+
type LoggerTagsFn = (...tags: string[]) => { tags: string[] }
function loggerTagsFactory (...defaultTags: string[]): LoggerTagsFn {
return (...tags: string[]) => {
}
}
+// ---------------------------------------------------------------------------
+
async function mtimeSortFilesDesc (files: string[], basePath: string) {
const promises = []
const out: { file: string, mtime: number }[] = []
loggerTagsFactory,
bunyanLogger
}
+
+// ---------------------------------------------------------------------------
+
+function removeCyclicValues () {
+ const seen = new WeakSet()
+
+ // Thanks: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value#Examples
+ return (key: string, value: any) => {
+ if (key === 'cert') return 'Replaced by the logger to avoid large log message'
+
+ if (typeof value === 'object' && value !== null) {
+ if (seen.has(value)) return
+
+ seen.add(value)
+ }
+
+ if (value instanceof Set) {
+ return Array.from(value)
+ }
+
+ if (value instanceof Map) {
+ return Array.from(value.entries())
+ }
+
+ if (value instanceof Error) {
+ const error = {}
+
+ Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] })
+
+ return error
+ }
+
+ return value
+ }
+}
+
+function getAdditionalInfo (info: any) {
+ const toOmit = [ 'label', 'timestamp', 'level', 'message', 'sql', 'tags' ]
+
+ return omit(info, toOmit)
+}