Skip to content

console.context() #193

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

Open
foolip opened this issue Jan 27, 2021 · 17 comments · May be fixed by #244
Open

console.context() #193

foolip opened this issue Jan 27, 2021 · 17 comments · May be fixed by #244
Assignees

Comments

@foolip
Copy link
Member

foolip commented Jan 27, 2021

In the spirit of #27 and #74 I'm filing issues about two additional console members I've spotted as part of foolip/mdn-bcd-collector#917.

console.context(name) is available in Chrome and Node.js, and returns a new object with a lot of the console members. This test gives some clues about what it does:
https://chromium.googlesource.com/v8/v8/+/23d0a6a5125d407655f2b7f6bb7263b4e05019d8/test/inspector/runtime/console-context.js

It looks like console.context('bla').log('hello') doesn't log anything in Node.js, but logs "hello" just like console.log("hello") would in Chrome.

Does anyone recognize what this is, and would it be useful to standardize? I expect not, but want to check.

@nchevobbe
Copy link

it was added as an experiment a while ago in Chrome: https://bugs.chromium.org/p/chromium/issues/detail?id=728767
it does provide a nice way to filter logs (as shown in https://twitter.com/hashseed/status/1337709432994750464)

we don't have such thing in Firefox as it's not part of the standard, but I can see it being useful

@domfarolino
Copy link
Member

Interesting, it is a shame that it was never standardized in Chrome. I've posted https://groups.google.com/a/chromium.org/g/devtools-dev/c/umeCeS3Bgcs to see if I can get someone from the Chromium DevTools team to lend a hand here, especially since @nchevobbe seems to think that this would be useful, and thus we have a shot at getting multi-vendor support.

@nchevobbe
Copy link

I filed a bug for Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1948870
We don't plan to work on this in the near future, but at least it's tracked

@domfarolino domfarolino self-assigned this Feb 25, 2025
@nchevobbe
Copy link

I'm planning to attempt specifying this. @domfarolino I see you assigned it to you, do you already started looking into it?

@domfarolino
Copy link
Member

Thanks for the update @nchevobbe, feel free to take a look. I've co-assigned you.

@haxiomic
Copy link

haxiomic commented Mar 11, 2025

I was hoping I could use this to solve other problems with console but it didn't work as my intuition would have guessed. I expected it to be a copy of the console object, including a copy of its state (active group, profile timer etc)

The problem I have with console is I often want to group messages into a meaningful group or context

console.group('example-request');
let data = await longRequest();
console.log('got data');
let image = await longRequest(data.url);
console.log('got image');
console.groupEnd();

The problem here is that the await here means we yield to executing other code and so all other logs will end up in our group

so you might see in the log

> example-request
    *unrelated-log ...
    *another unrelated log
    > example-request
        *more unrelated logs
        got data

i.e. unexpected nesting if the request is called multiple times and random other logs included in the group

console.context() would seem like the perfect solution:

const ctx = console.context('example-request')
ctx.group('request-group')
let data = await longRequest();
ctx.log('got data');
... (same as above but using ctx)

This way our group wouldn't be polluted by other messages during the awaits

> example-request
    got data
    got image

I think before we standardise console.context(), it would be good to specify how it should handle internal state, and if it cannot separate state I'd argue for renaming for clarity

@captainbrosset
Copy link

Thank you @nchevobbe for planning to work on the spec changes.

Note that we, on the Edge team, have been working on a plan to improve contextual logging in Chromium, and have an explainer document almost ready to go. Here is the PR: MicrosoftEdge/DevTools#323 if you want to see the current state of our proposal.

Let me at-mention the Edge PM who's leading this proposal so she's aware of this thread: @leahmsft.

Note that our explainer comes with a proposal to give contexts a color, and that we'd love for console.context() to accept a second argument to make this possible.
See an example screenshot from the explainer:

Image

@nchevobbe
Copy link

Note that we, on the Edge team, have been working on a plan to improve contextual logging in Chromium, and have an explainer document almost ready to go. Here is the PR: MicrosoftEdge/DevTools#323 if you want to see the current state of our proposal.

Let me at-mention the Edge PM who's leading this proposal so she's aware of this thread: @leahmsft.

Note that our explainer comes with a proposal to give contexts a color, and that we'd love for console.context() to accept a second argument to make this possible. See an example screenshot from the explainer:

Image

Thanks @captainbrosset for the heads up.
For the color option, I would go a bit further and have a pair option, backgroundColor and color, so the user have more control. I'd also mention that it should accept light-dark() colors so the context can adapt for light/dark mode (%c does work in that regard see https://nicolaschevobbe.com/2024/07/21/console-log-light-dark.html ).

I wonder if we should go even further and accept %c directly in the context name?
This reminds me that we have an issue to handle ANSI color codes (#197), and maybe we should support those here so we could have colors for context logs in Node as well

@captainbrosset
Copy link

I wonder if we should go even further and accept %c directly in the context name?

I'd keep the context customization rather simple and I think (although that would be implementation dependent) it should only apply to a context badge that appears before the message itself. The reason for this is that, this way, the context color(s) don't interfere with message colors, such as those coming from the warn and error methods, or the %c styling that a user might have done at the message level already.

So, I think I'm on board with the idea of color + backgroundcolor (and for a way for it to work in light and dark modes), but I wouldn't go further than this.

@captainbrosset
Copy link

So, I think I'm on board with the idea of color + backgroundcolor (and for a way for it to work in light and dark modes), but I wouldn't go further than this.

That said, if the way to make this work requires users to provide 4 colors (text and background colors for both light and dark themes), that's not great either. So, maybe accepting %c in the context name is the right way to go after all. Thank you Nicolas for proposing it.
I'd add that styling should be optional. Doing console.context('name') should work, and implementations can then decide to provide their own colors to the context name badge if they so wish.

@leahmsft
Copy link

Our explainer is live at: https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/ContextualLoggingWithConsoleContext/explainer.md

Please open an issue for feedback on the explainer. Any feedback would be greatly appreciated!

nchevobbe added a commit to nchevobbe/console that referenced this issue May 26, 2025
This specifies the console.context(label) method which
returns a new console namespace object with an optional
context name label.

Tests: TBD

Fixes whatwg#193
@nchevobbe nchevobbe linked a pull request May 26, 2025 that will close this issue
5 tasks
@nchevobbe
Copy link

Started a WIP PR for this method.
(I tried to keep things as simple as possible for now until I receive initial feedback, we can then discuss if/how to include the proposal for showing/adding colors to the context name)

@nchevobbe
Copy link

While working on this, I wondered about a few things:

  • I went with creating a new console namespace object as this allows us to not have to edit the specification too much, since existing stateful methods (grouping/timing) are already scoped per console namespace object. Note that this is not what the Chrome implementation does though (e.g. the returned object is missing context), but it's seems the right approach to me.
  • What happens if the provided context name isn't a string? this doesn't seem to be specified for other methods taking a label (e.g. console.time), but it's mentioned in https://github.com/whatwg/console/blob/main/NOTES.md#consoletime---label-conversion--conversion-errors
  • Should we expose the context name that was passed (e.g. console.contextName) ? I think it could be useful to avoid confusion when working with a given console namespace object.
  • Should the context name be mandatory? This is not what Chrome is doing at the moment. Even though it might not be useful to have an empty context name, it does make sense to default to an empty string, at least for the global console object. Or we could decide of having a default name, like Firefox does for console.time (label is "default")
  • Do we want the context name to be unique ? Again, that's not what Chrome is doing, but that's something that we do for console.time for example (even though it's unique per console namespace object, not per document)

Let's discuss :)

@captainbrosset
Copy link

captainbrosset commented May 26, 2025

Should the context name be mandatory? This is not what Chrome is doing at the moment. Even though it might not be useful to have an empty context name, it does make sense to default to an empty string, at least for the global console object. Or we could decide of having a default name, like Firefox does for console.time (label is "default")

Seeing that a non-negligible number of websites already use console.context() with no context name (see https://chromestatus.com/metrics/feature/timeline/popularity/5031), I think we need to make the name optional. This snippet (or an equivalent to it) is on many sites:

            try {
                -1 !== i.userAgent.indexOf("Chrome") && (sa = 0,
                a.console.context().debug(Object.defineProperty(Error(), "stack", {
                    get: function() {
                        return sa++,
                        ""
                    }
                })))
            } catch (t) {}

My guess is that this is part of a library that is used by many, and that they're doing this because it gives them a way to filter debug logs per file. I have not tested, but I think omitting the context name in Chrome ends up creating a new entry under the Verbose category in the Console sidebar named after the source file name:

Image

Do we want the context name to be unique ? Again, that's not what Chrome is doing, but that's something that we do for console.time for example (even though it's unique per console namespace object, not per document)

Forcing it to be unique means apps have to pass the context object around. Wouldn't it be simpler if you could just call console.context("same-name") with the same name multiple time to access a console context which you have not kept a reference to?

@nchevobbe
Copy link

Thanks for you answers @captainbrosset

Should the context name be mandatory? This is not what Chrome is doing at the moment. Even though it might not be useful to have an empty context name, it does make sense to default to an empty string, at least for the global console object. Or we could decide of having a default name, like Firefox does for console.time (label is "default")

Seeing that a non-negligible number of websites already use console.context() with no context name (see https://chromestatus.com/metrics/feature/timeline/popularity/5031), I think we need to make the name optional.

Sounds good

Do we want the context name to be unique ? Again, that's not what Chrome is doing, but that's something that we do for console.time for example (even though it's unique per console namespace object, not per document)

Forcing it to be unique means apps have to pass the context object around. Wouldn't it be simpler if you could just call console.context("same-name") with the same name multiple time to access a console context which you have not kept a reference to?

I'm not sure I'm on board with this. If multiple libraries use the same context name (or no context name), this would be confusing to consider them being the same context (even if in the end it shouldn't matter too much for the user). For example if you have something like this:

/* myScript.js */
const logger = console.context();
logger.time();
// …
logger.timeEnd();


/* someLibrary.js */
const logger = console.context();
logger.time();
// …
logger.timeEnd();

since time/timeEnd are scoped within their console namespace object, we'd have some potential issue if we're re-using the same object in the example above.

@nchevobbe
Copy link

I was hoping I could use this to solve other problems with console but it didn't work as my intuition would have guessed. I expected it to be a copy of the console object, including a copy of its state (active group, profile timer etc)

The problem I have with console is I often want to group messages into a meaningful group or context

console.group('example-request');
let data = await longRequest();
console.log('got data');
let image = await longRequest(data.url);
console.log('got image');
console.groupEnd();

The problem here is that the await here means we yield to executing other code and so all other logs will end up in our group

so you might see in the log

> example-request
    *unrelated-log ...
    *another unrelated log
    > example-request
        *more unrelated logs
        got data

i.e. unexpected nesting if the request is called multiple times and random other logs included in the group

console.context() would seem like the perfect solution:

const ctx = console.context('example-request')
ctx.group('request-group')
let data = await longRequest();
ctx.log('got data');
... (same as above but using ctx)

This way our group wouldn't be polluted by other messages during the awaits

> example-request
    got data
    got image

I think before we standardise console.context(), it would be good to specify how it should handle internal state, and if it cannot separate state I'd argue for renaming for clarity

In my PR, console.context() creates a new console namespace object, meaning that it should have its own state to handle its group stack, count map and timer table.
I think that the current Chrome implementation does provide an object with its own state. For example if you run the following:

console.time("hello");
console.context().timeEnd()

You get the following warning: Timer 'default' does not exist

I think the issue with console.group is more a UI issue, and you can already experience it today if you have a page with iframes: all console.group* method will impact the UI globally.
The spec is already clear about this and messages should appear in the right group:

The output produced by calls to Printer should appear only within the last group on the appropriate group stack if the group stack is not empty, or elsewhere in the console otherwise.

So I don't think there's anything specific we need to do at the moment; we should file bugs on implementers trackers so they would implement the spec (for Firefox we have https://bugzilla.mozilla.org/show_bug.cgi?id=1441771).
Note that, as mentioned in the bug, this kind of breaks the idea that all messages are displayed in a chronological order, e.g. if you have

console.log("message 1");
console.group("group 1");
console.context("myContext").log("message 2");
console.log("message 3")

the "correct" output would be:

08:00:00 | message 1
08:00:01 | ▼ group 1
08:00:03 | |  message 3
08:00:02 | message 2 [myContext]

that's also something that would be hard to do in the terminal (e.g. for Node/deno)

@terinjokes
Copy link
Collaborator

Groups are implementation defined, as is most of the UI of console. For example, I'd expect a server implementation to include group and context information as part of the key-values for a logfmt log line.

If implementors find that interactive groups while displaying multiple contexts is too confusing to users, they can certainly display them in other ways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

7 participants