mikser-io 10.7.0 → 10.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/logger.js +48 -21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mikser-io",
3
- "version": "10.7.0",
3
+ "version": "10.8.0",
4
4
  "files": [
5
5
  "app.js",
6
6
  "index.js",
package/src/logger.js CHANGED
@@ -498,10 +498,21 @@ onLoad(() => {
498
498
  //
499
499
  // A minimum TOTAL would fix the count and get the other half wrong: four PDFs
500
500
  // through Chrome is a small phase and a slow one, and it is exactly the phase
501
- // worth narrating. Elapsed time is what "long" means, it needs no per-phase
502
- // tuning, and it applies to the drawn path too — `finished: 5 0s` is the same
503
- // non-information in a terminal, and its own `0s` says so.
504
- export const PROGRESS_MIN_MS = 1000
501
+ // worth narrating. Elapsed time is what "long" means and it needs no
502
+ // per-phase tuning.
503
+ //
504
+ // It is an INTERVAL rather than a threshold, and quartiles are gone with it.
505
+ // A quartile is a fraction of the WORK, so it says nothing about how often a
506
+ // line appears: four records land in three seconds on a fast phase and four
507
+ // records cover an hour on a slow one. Time is the axis a reader cares about,
508
+ // so one line per interval, however much work passed in between.
509
+ //
510
+ // This gates the RUNNING commentary only. `progress-finished` is not behind
511
+ // it: every phase says that it ran and what it cost, whatever the duration.
512
+ // Gated, a short phase produced no record at all and a build could not say
513
+ // what it had done — and off a TTY that line is the only place phase timings
514
+ // come from.
515
+ export const PROGRESS_INTERVAL_MS = 30_000
505
516
 
506
517
  // Which item, not just how far. A phase name alone says a build is doing
507
518
  // something; the thing a stuck build needs to say is WHAT it is stuck on.
@@ -519,6 +530,12 @@ function progressDetail(detail) {
519
530
  return relative.startsWith('..') ? text : relative
520
531
  }
521
532
 
533
+ // `0s` for anything under a second reports the whole phase as nothing. Below
534
+ // a second the number IS the information.
535
+ function formatDuration(ms) {
536
+ return ms < 1000 ? `${ms}ms` : `${(ms / 1000).toFixed(1)}s`
537
+ }
538
+
522
539
  function emitProgress({ name, total, value, detail }) {
523
540
  const at = progressDetail(detail)
524
541
  const fields = { code: 'progress', phase: name, total, value }
@@ -551,7 +568,7 @@ export function trackProgress(name, total) {
551
568
  // --json would have extended that to every machine reading the output.
552
569
  // Losing the graphics is the point; losing the information is not.
553
570
  const drawn = !carriesDocument && Boolean(process.stdout.isTTY) && Boolean(runtime.options.info)
554
- currentBar = { name, total, value: 0, started: Date.now(), drawn, milestone: 0, detail: null }
571
+ currentBar = { name, total, value: 0, started: Date.now(), drawn, lastReport: Date.now(), detail: null }
555
572
  if (drawn) ensureGauge().show({ section: name, subsection: `0/${total}` }, 0)
556
573
  }
557
574
 
@@ -567,17 +584,15 @@ export function updateProgress(detail) {
567
584
  if (drawn) {
568
585
  gauge?.show({ section: name, subsection: `${value}/${total}` }, value / total)
569
586
  } else {
570
- // Quartiles, not every item: a bar redraws in place and costs one
571
- // line, a log record does not. 800 documents is 800 lines of noise if
572
- // this counts the way the bar does.
573
- //
574
- // The milestone advances whether or not the record is emitted. Held
575
- // back, every quartile the phase passed under the threshold would fire
576
- // in a burst the moment it crossed.
577
- const reached = Math.floor((value / total) * 4)
578
- if (reached > currentBar.milestone && value < total) {
579
- currentBar.milestone = reached
580
- if (Date.now() - currentBar.started >= PROGRESS_MIN_MS) emitProgress(currentBar)
587
+ // One line per interval, not per item and not per quartile: a bar
588
+ // redraws in place and costs one line, a log record does not, so 800
589
+ // documents is 800 lines of noise if this counts the way the bar does.
590
+ // A phase that finishes inside the interval says nothing at all while
591
+ // it runs its finished line covers it.
592
+ const now = Date.now()
593
+ if (now - currentBar.lastReport >= PROGRESS_INTERVAL_MS && value < total) {
594
+ currentBar.lastReport = now
595
+ emitProgress(currentBar)
581
596
  }
582
597
  }
583
598
  if (value >= total) stopProgress()
@@ -592,14 +607,26 @@ export function stopProgress() {
592
607
  // Structured either way, so a machine reading --json's stderr gets the
593
608
  // same facts a person reads off the bar.
594
609
  //
595
- // A phase that did not finish is worth a line at any duration — it is a
596
- // warning, not progress, and the whole point is that it is unexpected.
610
+ // This line has to stand alone. With the running commentary on an
611
+ // interval it is the ONLY record most phases produce, and `Documents
612
+ // import finished: 5 0s` said neither what the five were nor how long it
613
+ // took — a count with no subject and a duration rounded away to nothing.
614
+ //
615
+ // The subject is the PHASE, not an item. The last entity a phase happened
616
+ // to walk is not what the phase was about: seven journal phases in a row
617
+ // reported the same `/layouts/page.hbs` because that is where the walk
618
+ // ended, and `Files import finished: 3, last .../social-fb.svg` put a
619
+ // filename into the build log that nothing had anything to say about — it
620
+ // broke a test asserting that file is never mentioned, which is exactly
621
+ // the misreading it invites. `Files import finished: 3 in 3ms` already
622
+ // says what finished, how much of it, and what it cost. The running
623
+ // records keep the item, because there it shows MOVEMENT.
597
624
  if (value < total) {
598
625
  logger.warn({ code: 'progress-unfinished', phase: name, total, value, missing: total - value },
599
- '%s unfinished: %d', name, total - value)
600
- } else if (ms >= PROGRESS_MIN_MS) {
626
+ '%s unfinished: %d of %d after %s', name, total - value, total, formatDuration(ms))
627
+ } else {
601
628
  logger.info({ code: 'progress-finished', phase: name, total, ms },
602
- '%s finished: %d %ds', name, total, Math.round(ms / 1000))
629
+ '%s finished: %d in %s', name, total, formatDuration(ms))
603
630
  }
604
631
  currentBar = null
605
632
  }