Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 1x 1x 4x 4x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 1x 1x 1x 1x 4x 4x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 1x 1x 4x 4x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 1x 1x 4x 4x 4x 3x 4x 3x 3x 3x 3x 3x 3x 3x 3x 4x 4x 4x 4x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | const { Logging } = require('@google-cloud/logging')
const GoogleCloudAdapter = require('../GoogleCloudAdapter')
const { FirestoreAdapter } = require('../firestore')
const { ErrorUtils } = require('../../../utils')
const $errorUtils = new ErrorUtils()
const $fs = new FirestoreAdapter({ databaseId: 'settings' })
type TEnvironment = 'development' | 'qa' | 'uat' | 'production'
type TProps = {
message: any
labels?: object
}
type TLogEntry = {
severity: 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR'
env: string
log_name: string
labels?: object
message: string
}
type TLogLevel = 'debug' | 'info' | 'warn' | 'error'
const LOG_LEVELS: Record<
TLogLevel,
{ severity: TLogEntry['severity']; level: number }
> = {
debug: { severity: 'DEBUG', level: 0 },
info: { severity: 'INFO', level: 1 },
warn: { severity: 'WARNING', level: 2 },
error: { severity: 'ERROR', level: 3 },
}
export class LoggingAdapter extends GoogleCloudAdapter {
private static instance: LoggingAdapter | null = null
private settingsPromise: Promise<void> | void | null = null
private logLevel: TLogLevel = 'info'
private env: TEnvironment | null = 'development'
private service: string | null = 'no-service'
private executionContext: string | null = null
private initialized = false
// Keep a single Logging instance
private logging: typeof Logging
private constructor() {
super()
// Initialize Logging just once
this.logging = new Logging()
// Attempt to auto-detect resource (optional based on environment)
// If you do not need this, you can remove or call it in an async init step.
this.logging.setDetectedResource().catch((err) => {
console.error('Error setting detected resource:', err)
})
}
public static getInstance(): LoggingAdapter {
if (!LoggingAdapter.instance) {
LoggingAdapter.instance = new LoggingAdapter()
}
return LoggingAdapter.instance
}
public getState() {
return {
initialized: this.initialized,
logLevel: this.logLevel,
env: this.env,
service: this.service,
executionContext: this.executionContext,
}
}
async initializeSettings(
env: TEnvironment,
service: string,
executionContext: string
): Promise<void> {
if (!env || !service || !executionContext) {
throw new Error('Missing required parameters for initialization')
}
this.env = env
this.service = service
if (executionContext !== this.executionContext) {
this.executionContext = executionContext
this.settingsPromise = null
this.initialized = false
}
if (this.initialized) {
return Promise.resolve()
}
try {
if (!this.settingsPromise) {
this.settingsPromise = this.fetchLogSettings()
}
await this.settingsPromise
this.initialized = true
} catch (error) {
console.error('initializeSettings - Error fetching log settings:', error)
this.initialized = false
this.settingsPromise = null
throw $errorUtils.errorHandler(error)
}
}
private async fetchLogSettings(): Promise<void> {
if (!this.service) {
console.error('fetchLogSettings - Service not initialized')
throw new Error('Service not initialized')
}
try {
const settings = await $fs.getDoc({
collection: 'microservices',
id: this.service,
})
if (settings && settings.logLevel) {
this.logLevel = settings.logLevel as TLogLevel
}
return Promise.resolve()
} catch (error) {
console.error('fetchLogSettings - Error fetching log settings:', error)
throw $errorUtils.errorHandler(error)
}
}
// Use log levels to decide whether to log
private shouldLog(level: TLogLevel) {
return LOG_LEVELS[level].level >= LOG_LEVELS[this.logLevel].level
}
private ensureInitialized() {
if (!this.initialized) {
throw new Error('LoggingAdapter not initialized')
}
}
private writeEntryAsync(props: TLogEntry) {
// Fire & forget: we don’t await the result
;(async () => {
try {
const { severity, env, log_name, labels } = props
let { message } = props
// Format message
if (typeof message === 'object') {
message = JSON.stringify(message)
}
message = `${log_name}: ${message}`
if (env !== 'production') {
message += ` (${env})`
}
// Use log(...), not logSync(...)
const log = this.logging.log(log_name)
const metadata = {
resource: { type: 'global' },
labels: {
...labels,
env,
service: log_name,
},
severity,
}
const entry = log.entry(metadata, message)
// Because log.write() returns a Promise (with .log()),
// you can do:
log
.write(entry)
.then(() => {
// optional: console.log('Log written')
})
.catch((err) => {
console.error('Logging write error:', err)
})
} catch (err) {
console.error('writeEntryAsync outer error:', err)
}
})()
}
// Log methods
private log(level: TLogLevel, props: TProps) {
this.ensureInitialized()
if (!this.shouldLog(level)) return
if (!this.env || !this.service) {
throw new Error('LoggingAdapter not initialized properly')
}
try {
const severity = LOG_LEVELS[level].severity
// Fire and forget:
this.writeEntryAsync({
severity,
env: this.env,
log_name: this.service,
labels: props.labels ?? {},
message: props.message,
})
} catch (error) {
// If you're willing to swallow the error at this stage, do so
// or if you'd rather bubble it up, re-throw
console.error('log error:', error)
}
}
debug = (props: TProps) => {
this.log('debug', props)
return true
}
info = (props: TProps) => {
this.log('info', props)
return true
}
warn = (props: TProps) => {
this.log('warn', props)
return true
}
error = (props: TProps) => {
this.log('error', props)
return true
}
}
|