It seems you want a logger where the key determines (part of) what is logged. This is somewhat normal, however the approach here is bad because you lose control over your API. You can have a typo like logger.erro("500")
and your code would work but your logs will now come out as [ERRO] - 500
. This in turn messes up any log analysis you might do, the simplest of which is just searching for [ERROR]
.
Instead, the usual approach here is to have a method on the logger that can take the parts of the message and then log it uniformly. In your case, it seems you want a prefix and a message. You can then expose methods with pre-defined prefix part.
Using class syntax
class CustomLogger {
log(prefix, msg) {
console.log(`[${prefix}] - ${msg}`)
}
trace(msg) {
this.log("TRACE", msg);
}
info(msg) {
this.log("INFO", msg);
}
warn(msg) {
this.log("WARN", msg);
}
error(msg) {
this.log("ERROR", msg);
}
}
let logger = new CustomLogger();
logger.error("404"); // "[ERROR] - 404"
logger.info("user signed up"); // "[INFO] - user signed up"
Using an object literal
let logger = {
log(prefix, msg) {
console.log(`[${prefix}] - ${msg}`)
},
trace(msg) {
this.log("TRACE", msg);
},
info(msg) {
this.log("INFO", msg);
},
warn(msg) {
this.log("WARN", msg);
},
error(msg) {
this.log("ERROR", msg);
},
}
logger.error("404"); // "[ERROR] - 404"
logger.info("user signed up"); // "[INFO] - user signed up"
If the above seems like too much code, then consider the following:
Derive your methods
Using currying to perform partial application.
const log = prefix => msg =>
console.log(`[${level}] - ${msg}`);
let logger = {
trace: log("TRACE"),
info : log("INFO"),
warn : log("WARN"),
error: log("ERROR"),
}
logger.error("404"); // "[ERROR] - 404"
logger.info("user signed up"); // "[INFO] - user signed up"
Using the approach where you only expose the methods you want makes it easier to change the implementation if needed. The consuming code will not need to be aware of this. Consider if you actually want to have different log levels as well as a prefix and a message part. If you have completely dynamic methods, then you can hardly do this. How are you going to distinguish logger.info
from logger.error
when they both just call the same code? You could try to do a big conditional chain but then what you end up doing is implementing all possible methods in one place.
Instead here is how the above code can change:
const log = level => prefix => msg => //take `level`
console[level](`[${prefix}] - ${msg}`); //use `level`
let logger = {
trace: log("info")("TRACE"),
info : log("info")("INFO"),
warn : log("warn")("WARN"),
error: log("error")("ERROR")
}
logger.error("404"); // "[ERROR] - 404"
logger.info("user signed up"); // "[INFO] - user signed up"
Minimal change for the consuming code and the logger itself.