10 日目の記事です。

console オブジェクトを眺めていたら見慣れない console.context() というのに気付きました。Chrome 以外にはなさそう? 使ってるって話を聞いたことがない? 彼氏彼女はいるの? 調べてみました!

先にまとめ

  • 2017 年に追加された V8 の試験的な機能らしい
  • 本来は、コンソールのサイドパネル(左側)でフィルタリングできるものだった様子
  • 今は、特に有意義に使えないっぽい
  • Chrome DevTools Protocol に残滓を発見。Puppeteer で利用可能

カスタムログ機能

こちらの 2017 年の記事に紹介がありました。

こんな感じで使うようです。(このコード自体は 2020 年現在でも動作しました。)

const logger = console.context('My Logger');
logger.log('Hi');

console.context("name") で名前 "name" を付けて新しいコンテキストを作成しそれを用いてログと取ると、DevTools コンソールのサイドバーにその名前 "name" が現れ、フィルタリングできる、というものだったようです。

例えばこう↓書くと、3rd Party、Info、Requests の 3 つの分類が作られサイドパネルに表示されます。

const thirdPartyLogger = console.context('3rd Party')
const infoLogger =  console.context('Info')
const requestsLogger =  console.context('Requests');

サイドバーを開いた様子。作成した 3 種類のコンテキストの名前が表示されている。画像は umaar.com から。

現在の状況

Chrome

エラーにはならないが通常の console オブジェクトを利用する場合と変わらない。

DevTools Console パネルのサイドバーはエラーレベルの分類を選択して表示をフィルタリングする機能があるが、console.context() で作成してもこの一覧に表示されるようなことはなかった。

現在の Chrome 87 でサイドバーを開いた様子。エラーレベルによる分類となっている。

Firefox、Safari

該当機能なし、undefined。まあ V8 の話なので。

Living standard

記載なし。

ちなみに Chrome の方も載ってないです。

Node.js

V8 を利用している Node.js。API 一覧には載ってないけど手元の v14 でも実装は残っていた。

ただし、エラーは出ないもののログはどこにも出力されないので意味がない。どこかで拾えるのかな。

$ node
Welcome to Node.js v14.15.1.
Type ".help" for more information.
> c = console.context('My Logger');
{
  debug: [Function: debug],
  error: [Function: error],
  info: [Function: info],
…
}
> c.log('Hi');
undefined

Puppeteer

探していたら、Chrome DevTools Protocol で言及を見つけた。

コンソールが利用された際に発火するイベント。context にコンテキストの名前が格納されるらしい。

string

Console context descriptor for calls on non-default console context (not console.*): ‘anonymous#unique-logger-id’ for call on unnamed context, ‘name#unique-logger-id’ for call on named context. [EXPERIMENTAL]

string

デフォルトでないコンソールコンテキストでの呼び出し(※ console.* ではないもの)のコンソールコンテキスト記述子ディスクリプター。名前なしコンテキストでの呼び出しは ‘anonymous#unique-logger-id’ に、名前ありコンテキストでの呼び出しは ‘name#unique-logger-id’ になる。 [実験的]

Puppeteer で試したら、たしかに飛んできた! やった! まだ使える!!(?)

const puppeteer = require('puppeteer');

main();

async function main(){
  console.log(`creating browser...`);
  const browser = await puppeteer.launch({
    headless: false,
    defaultViewport: null,
    devtools: true,
    args: ['--window-size=500,500','--window-position=0,0']
  });

  console.log(`getting page...`);
  const page = (await browser.pages())[0];

  console.log(`connecting to DevTools...`);
  const client = await page.target().createCDPSession();

  await client.send('Runtime.enable');

  client.on('Runtime.consoleAPICalled', (data) => {
    const { context } = data;
    console.log('Logged in:', context);
  });

  const code = `
    console.log('Yo');

    c1 = console.context('apple');
    c1.log('one');

    c2 = console.context('banana');
    c2.log('one');
  `;
  client.send('Runtime.evaluate', {
    expression: code,
  });
};
$ node index.js
creating browser...
getting page...
connecting to DevTools...
Logged in: undefined
Logged in: apple#1
Logged in: banana#2

うおおお!

DevTools での扱いを知りたかったけど

V8 の Git ログを見ると 2017 年に実装されたみたい。いやあでも覗いてみたけど全然わかんないですね。

console_context_id_symbol, console_context_name_symbol というのが見つかった。そこら辺のコードはどうも 4 年前から変わってないっぽい。

で、V8 じゃなくて Chromium DevTools コンソールの側でどう扱われているか。

console_context_ で検索しても該当なし。

イベントの Runtime.consoleAPICalled はいくつかあって、OnConsoleAPICalled みたいな関数も。 逆に量が多くて追い切れなかった。

あと console-filter-test.js というファイルに console.context() の記述があるのを発見。でも正直この試験の読み方わかんないなあ。console.context はこの 2 行のみ。

というか Console パネルの実装の方を見ると良いのかな? サイドパネルの更新を履歴から追えれば……でも引きやすいクラス名も付いてないし初見でこの規模のファイルツリーを掘るのも…… UI の文章なら…… console-filter-sidebar-expected.txt ……え、なにこれどうやって使われてるの……。

なんかもう大変そうなので諦め……。

その他

ログのフィルタリング

コンソールパネル上部でフィルタリングができます。ログ出力の際に名前を付けるようにして、その名前でフィルタリングすると便利です。例えばこういうログ出力を書くようにして。

console.log('[MyLog]', value1, value2);

フィルターとして "[MyLog]" を与えてやれば、必ずこの系統のログのみが出てくるようになります。

おしまい

DevTools の方の動向は、調べてみたけどよくわかりませんでした案件となってしまいました。はいいかがでしたか?

というわけで API 利用者任意に分類できる V8 の機能っぽいんだけど、バックエンドの V8 としては機能は動いてる一方でフロントエンドの Chrome DevTools で使えない、という感じのようです。続きは Chromium にお詳しいどなたかお願いします……。気になる……。

普通に使えるようになってたら便利だったかもね。

参考