-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restructuring log middleware #10
Conversation
caae990
to
d035515
Compare
const traceparent = req.header("traceparent") || createTraceparent(); | ||
const trace = getTraceFromTraceparent(traceparent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should combine these rows, since we might get no trace
if the header was invalid. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think both variants work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll leave it like this for now then 😄
Probably easier to notice somethings wrong if the trace doesn't exist vs some random other trace is there instead.
const traceparent = req.header("traceparent") || createTraceparent(); | ||
export type Middleware = () => RequestHandler; | ||
|
||
export const middleware: Middleware = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps also rename this to something better too. Prefix with create? Or should it be called something less generic over all - app.use(logStoreMiddleware())
or app.use(logTracingMiddleware())
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think middleware
is ok. We're only exporting 1 middleware in this lib and callers are free to rename it when they import it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perfect! I've always felt torn on this topic, since named exports affect implementors this way. But I'm happy with this approach.
One thing that I changed was to remove |
export function decorateLogs(obj: Record<string, unknown>) { | ||
const store = getStore(); | ||
|
||
const gcpProjectId = getGcpProjectId(); | ||
if (!gcpProjectId) return logData; | ||
if (!store) throw new Error("@bonniernews/logger middleware has not been initialized"); | ||
|
||
return { | ||
...logData, | ||
"logging.googleapis.com/trace": `projects/${gcpProjectId}/traces/${trace.traceId}`, | ||
"logging.googleapis.com/spanId": trace.parentId, | ||
"logging.googleapis.com/trace_sampled": trace.isSampled, | ||
}; | ||
for (const key in obj) { | ||
store.logFields[key] = obj[key]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we need this as a separate function. Also, in this form, you can only add static data to your logs, which might not be that interesting. My thought was to add an optional argument to the middleware
factory function, that can add logging data from the Request
object. something like:
type MiddlewareConfig = {
extractRequestData?: (request: Request) => Record<string, unknown>;
};
export const middleware: Middleware = ({ extractRequestData }: MiddlewareConfig = {}) => {
return (req, _res, next) => {
...
if (extractRequestData) {
extra = extractRequestData(req);
for (const key in obj) {
logFields[key] = obj[key];
}
}
...
This way, you also don't have to keep track of whether the storage has been initalized or not, it's all done in the middleware.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My specific use case in greenfield is extracting the IAP headers to log which service account made a specific request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that type of middleware option function is great! But I think its nice to have a separate decorateLogs
type function that you can use anywhere in your application, such as if (user) { decorateLogs(...) }
. Lets att that middleware option in the next PR 🙏
I can remove the extra function 👌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, I misunderstood. I thought you were referring to another function. I think separating the argument on the middleware from decorateLogs() could be nice, since they cover different use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, so the idea is to write my own middleware where decorateLogs
is called? That is probably even more flexible actually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you can either call it inside your own middleware, or anywhere in the request flow. I have used it on Di's site in some conditional logic before.
const traceparent = req.header("traceparent") || createTraceparent(); | ||
const trace = getTraceFromTraceparent(traceparent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think both variants work.
The only reason to keep it as a separate field is to log it properly if we run outside GCP, so maybe add it back if we don't have a |
Ah, of course! I will do that 🥳 |
I like this approach a lot. Have my 👍 What do you think about always logging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Vi kör!
No description provided.