After reading Martin Fowler's blog on domain oriented observability, I was inspired to implement this concept without relying on classes. However, I encountered some challenges involving generics in TypeScript. Here is the snippet of my code (the error occurs towards the end):
import { Obj } from '../model/types';
interface Logger {
}
interface RouterLogger extends Logger {
requestReceived: () => void
}
interface ExecutorLogger extends Logger {
apiFound: () => void,
templateLoaded: () => void
apiExecuted: () => void
apiRunEnded: () => void
}
interface TemplaterLogger extends Logger {
templateRequestFired: () => void
respondedSuccessfully: () => void
respondedWithError: () => void
}
interface ApiLogger extends Logger {
apiRequestFired: () => void,
respondedSuccessfully: () => void,
respondedWithError: () => void,
}
const loggers = {
router: ({ data, metadata }: Obj): RouterLogger => ({
requestReceived: () => {
console.log('Request Received', data, metadata)
// some rabbitMQ messaging
// etc
},
}),
executor: (context: Obj): ExecutorLogger => ({
apiFound: () => { },
templateLoaded: () => { },
apiExecuted: () => { },
apiRunEnded: () => { },
}),
templater: (context: Obj): TemplaterLogger => ({
templateRequestFired: () => { },
respondedSuccessfully: () => { },
respondedWithError: () => { },
}),
externalApi: (context: Obj): ApiLogger => ({
apiRequestFired: () => { console.log('request sent', context) },
respondedSuccessfully: (response) => { console.log('success', context, response) },
respondedWithError: () => { },
})
}
function getLoggerDispenser<T extends Logger>(domain: keyof typeof loggers) {
return (context: Obj): T => loggers[domain](context); //'RouterLogger' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Logger'
}
export {
Logger,
RouterLogger,
ExecutorLogger,
ApiLogger,
getLoggerDispenser,
}
The issue I am facing regarding exporting generic Loggers seems apparent - there must be a more efficient way to achieve this. Any guidance in finding a solution would be greatly appreciated.
EDIT: Please note that I am utilizing partial application when obtaining the logger, enabling me to initialize the logger with a context
for simplified logging once all necessary data is available.
EDIT 2 (refer to the updated code above for an example using the context
): An instance where this setup would come into play:
const externalApiLogger = getLoggerDispenser('externalApi')({ jobId: 1, issuerId: 34 })
// send request
externalApiLogger.apiRequestFired()
// read response = success
externalApiLogger.respondedSuccessfully(response)