Well the premise here is that in your internal layers know nothing from externals ones, so any interfaces you use in your domain should lays in the domain, that gives you the hability to change how you log later without making a single change in your business logic, so just create a Log interface in your domain, implement it from outside and voila.
In your domain it could looks like this:
interface ILogger {
log(level: string, message: string): void
}
class MyUseCase {
public constructor(private readonly logger: ILogger){}
public execute(input: Input): void {
// some stuff
this.ILogger.log('level', 'message')
// some other stuff
}
}
and in your framework and drivers layers you could:
class MyLogger implements ILogger {
log(level: string, message: string): void {
myChosenLoggerTech.log(level, message) // ie winston, console.log, etc
}
}
So now when MyUseCase
is instantiated can use:
new MyUseCase(new MyLogger())
But wait, nothing is that simple, generally speaking there are two log use cases:
- You want to log business info
- You want to log app status info
All right, if your case is number 2 go with this solution, but if your case is number 1 maybe you should make the action of logging more explicit by wrapping it into a dedicated entity, or exception or whatever truly represents your business.
You can check here for a more detailed explanation.