Skip to content

fix(logs): detect microsecond and nanosecond epoch timestamps #74

Description

@xe-nvdk

Found while reviewing #67 (the fix for #54). Pre-existing and out of scope there, so filing separately.

The gap

isTimestampValue in src/lib/logFieldDetector.ts recognises epoch values by digit count:

// Unix timestamp (10 or 13 digits)
if (/^\d{10,13}$/.test(str)) return true;

That covers seconds (10 digits) and milliseconds (13). It does not cover microseconds (16) or nanoseconds (19), which fall through to the permissive new Date(str) fallback and return false — new Date("1767225600000000000") is Invalid Date.

Arc is a nanosecond-precision store. epoch_ns is what the $__timeGroup macro emits, and a log table written with nanosecond timestamps is an ordinary thing to have, so this is the one epoch width most likely to show up and the one we do not detect.

Why it matters

detectLogFieldsWithData falls back to value-based detection when no column name matches. A table whose timestamp column is named something unrecognised (ts_ns, observed, ingested) and holds nanoseconds gets no timestamp detected at all, so Log Explorer cannot build a time filter or order the results.

If a different column in the same row happens to look like a timestamp, that one is chosen instead — which is the #54 failure mode reached from the other direction.

What to do

Extend the digit-count check to the epoch widths Arc can produce, and decide the unit from the magnitude rather than the digit count alone — frame.ts already does this well in detectEpochUnit, using the median magnitude of a sample rather than the first value, precisely because one outlier row otherwise picks the wrong unit. Reuse that approach rather than inventing a second one; the two should not disagree about what 1767225600000000000 means.

Watch for:

  • A digit-count check is not a magnitude check. A 16-digit number is microseconds only if it lands in a plausible date range; 9999999999999999 is not a timestamp. Range-check the resulting instant the way the existing fallback does (> 2000, < 2100).
  • Do not regress fix(logs): tighten timestamp detection #67's fix. Bare small integers (1..12, 2001..2099) must stay rejected — that is the whole point of fix(logs): isTimestampValue accepts bare integers, misdetecting numeric columns as the timestamp #54. Only widths that cannot be confused with an ordinary counter should be accepted.
  • Number.MAX_SAFE_INTEGER is 9007199254740991, 16 digits. A 19-digit nanosecond value exceeds it, so parsing it through Number loses precision. Compare as a string or use BigInt for the range check.

Good first issue notes

Self-contained: one function in src/lib/logFieldDetector.ts plus tests in src/lib/logFieldDetector.test.ts, which already has a table-driven style to extend. Read detectEpochUnit in src/lib/dashboard/frame.ts first — the reasoning you need is written out there, including why the median is used instead of the first value.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomers

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions