Skip to content
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

Merged
merged 6 commits into from
Nov 12, 2024
Merged

Restructuring log middleware #10

merged 6 commits into from
Nov 12, 2024

Conversation

wisko
Copy link
Contributor

@wisko wisko commented Nov 8, 2024

No description provided.

@wisko wisko force-pushed the fix/middleware-signature branch from caae990 to d035515 Compare November 8, 2024 16:05
Comment on lines +33 to +34
const traceparent = req.header("traceparent") || createTraceparent();
const trace = getTraceFromTraceparent(traceparent);
Copy link
Contributor Author

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?

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

@wisko wisko requested a review from MattiasOlla November 8, 2024 16:11
const traceparent = req.header("traceparent") || createTraceparent();
export type Middleware = () => RequestHandler;

export const middleware: Middleware = () => {
Copy link
Contributor Author

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())?

Copy link
Contributor

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.

Copy link
Contributor Author

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.

@wisko
Copy link
Contributor Author

wisko commented Nov 8, 2024

One thing that I changed was to remove spanId as its own log field, since its value already existed in logging.googleapis.com/spanId (unlike the traceId). I can bring it back if we want? Otherwise I just need to update some tests.

Comment on lines +13 to +20
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];
}
Copy link
Collaborator

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.

Copy link
Collaborator

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.

Copy link
Contributor Author

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 👌

Copy link
Contributor Author

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.

Copy link
Collaborator

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.

Copy link
Contributor Author

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.

Comment on lines +33 to +34
const traceparent = req.header("traceparent") || createTraceparent();
const trace = getTraceFromTraceparent(traceparent);
Copy link
Collaborator

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.

@MattiasOlla
Copy link
Collaborator

One thing that I changed was to remove spanId as its own log field, since its value already existed in logging.googleapis.com/spanId (unlike the traceId). I can bring it back if we want? Otherwise I just need to update some tests.

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 gcpProjectId?

@wisko
Copy link
Contributor Author

wisko commented Nov 11, 2024

One thing that I changed was to remove spanId as its own log field, since its value already existed in logging.googleapis.com/spanId (unlike the traceId). I can bring it back if we want? Otherwise I just need to update some tests.

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 gcpProjectId?

Ah, of course! I will do that 🥳

@wisko wisko marked this pull request as ready for review November 11, 2024 13:00
@wisko wisko changed the title WIP: Restructuring log middleware Restructuring log middleware Nov 11, 2024
@assensamuelsson
Copy link
Contributor

I like this approach a lot. Have my 👍

What do you think about always logging spanId even for GCP services? This is how we described the standard in the technical principles PR right now. It is somewhat redundant but keeps message structure consistent regardless of where the application is hosted.

Copy link
Collaborator

@MattiasOlla MattiasOlla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vi kör! :shipit:

@wisko wisko merged commit 942fa40 into main Nov 12, 2024
2 checks passed
@wisko wisko deleted the fix/middleware-signature branch November 12, 2024 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants