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

QUESTION: MDC support for bunyan like java logback and log4j had???? #722

Open
deanbiltup opened this issue Aug 8, 2024 · 3 comments
Open

Comments

@deanbiltup
Copy link

deanbiltup commented Aug 8, 2024

We do not want any logic depending on protocol(http, gRPC) and we keep our client API and server API 100% the same. in fact, we want to share the API to both and generate the client and generate the mapping of http request to controller call like we have done in java in the past. HOWEVER, we also want a filter that stamps a unique request id AND takes username from cookie and puts it in MDC.put("userId", username) as well. Then in plain old typescript with no access to http request/response as it could be thrift, http, gRPC re-using the same plain old code, we want this log

log.info("starting)

to print out that requestID and userId.

Looking at the example here https://cloud.google.com/logging/docs/setup/nodejs it looks like one has to have access to the request object leaking http into the plain old typescript code.

Our code though is plain typescript request DTO and response DTO and plain old typescript not knowing about the protocol as seen here -> https://github.com/deanhiller/ts-prototype/blob/main/server/src/controllers/baseController.ts

This BaseController implements BaseApi which the react code re-uses the same BaseApi so if BaseApi changes, both server and client both change in a 100% the same fashion.

Is there another way???

@deanbiltup
Copy link
Author

ANOTHER ID: What if we had a Map of 'requestID' -> MDCContextMap. Downside is I have to pass requestId throughout. upside is in the filter at top

Filter ->

const requestId = generateNewId();
const globalMap = new Map<string, MDCContextMap>();
global.put(requestId, new MDCContextMap());

//user defined MDC fields
global.get(requestId).put("userName", getCurrentLoggedInUserName());
global.get(requestId).put("subRequest", getSomeOther());
//any other contexts can be added later in the code as well usually done from a batch for loop later.

try {
   return await invokeController(request, requestID);
} finally {
    globalMap.remove(requestId);
}

kind of hacky though as every log has to have log.info(requestId, "Log something");

but now the logger json output has access to all fieldds in the MDCContextMap that a user adds

@deanbiltup
Copy link
Author

Is there someone in core typescript javascript features we can request they port the slick solution from Twitter's Promise.scala / Context.scala. It combined ThreadLocal with passing the Map context over the async boundary to be re-instated on the callback. It was very slick so in java, I never pass around requestId or loggers and I just create loggers and log.

@deanhiller
Copy link

deanhiller commented Aug 14, 2024

I found some references to AsyncLocalStorage and it works when I use it personally but when setup for Bunyan, it is not logging my values. I have the following code

const logger: Logger = bunyan.createLogger({ // The JSON payload of the log as it appears in Cloud Logging // will contain "name": "my-service" name: 'my-service', streams: streams , serializers: { req: () => { const store = asyncLocalStorage.getStore(); const value = store ? store.get('requestId') : undefined; console.log("we are here. store="+store+" email="+value); return { method: store ? store.get('method') : undefined, url: store ? store.get('url') : undefined, remoteAddr: store ? store.get('remoteAddr') : undefined, // Include the requestId in each log entry requestId: store ? store.get('requestId') : undefined, userId: store ? store.get('userId') : undefined }; } } });

I have this code and am expecting bunyan to log userId as console.log is logging it if I manually get it from the async storage ->

`
async fetchMe(request: FetchUserRequest): Promise {
const store = asyncLocalStorage.getStore();
const userId = store.get('userId');

    console.log(`userId=${userId}`); //logs it correctly

    this._logger.info("Should magically log it userId"); //does not log userId

    this._logger.info({}, "or this should magically log it??"); //does not log userId

`

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

No branches or pull requests

2 participants