I generally do line delimited JSON output for stdout logging in production environmnets. This lends itself very well to log shipping and ingestion into services like ELK-stack and Cloudwatch etc.
For JS based services, I will enrich the context object with logging/timing support that will add in a few bits from the request object (path, method, etc). It tends to work pretty well.
The shape of my log entries are usually along the lines of...
{
level: Enum(LogLevel)
timestamp: DateTime,
message: String
req: {
path: String,
search: String,
started: DateTime,
elapsed: Number/Decimal (ms) - since started
},
res?: {
status: Number,
statusText: String,
comment?: String,
},
error?: Error
details?: Object
}
The signature's for logging are like...
ctx.log.debug
(message: string, details?: any) => ...
(error: Error, details?: any) => ...
res bits from ctx if set/available and not part of the error or details (status/statusText/comment). Message will come from the error, when passing an error.
It's tended to work pretty well.. I fclone the error/details object(s) for safety... errors will graft back a few pieces that are hidden from enumerated properties (trace, etc)... Depends on the LOG_LEVEL though.