Skip to main content

loganalyzer

Triage toolkit for Background Geolocation SDK logs. Turns an iOS or Android capture into a digest — what happened, what went wrong — and an interactive map: the route, the events on it, and a time navigator for captures that span days.

If you have a tracking problem and a log, this tells you what the SDK was doing, and gives you something you can paste into an issue.

uvx transistorsoft-loganalyzer background-geolocation.log.gz --open

Install

The tool is Python, but you don't need to manage Python. uv brings its own:

# one-off, nothing installed
uvx transistorsoft-loganalyzer <file> --open

# or install the command
uv tool install transistorsoft-loganalyzer
loganalyzer <file> --open

If you already run Python 3.11+, pipx install transistorsoft-loganalyzer works too.

Getting a log

Call emailLog() in your app — the SDK writes a .log.gz and hands it to the share sheet. Both .log and .log.gz are accepted, as are several at once.

BackgroundGeolocation.emailLog("you@example.com");

Commands

Analyze

loganalyzer <files...> [--out DIR] [--map] [--open] [--locations] [--year YYYY]

Platform is grammar-sniffed, not guessed from the filename. Duplicates and unrecognized files are skipped with a note.

flag effect
--out DIR output root (default loganalyzer-out/); one subfolder per input
--map also write map.html
--open open each map in a browser tab (implies --map)
--locations also write locations.geojson
--year YYYY base year for Android's year-less timestamps (inferred otherwise)
--no-redact disable pseudonymization — local drill-down only

Drill into a moment

loganalyzer <file> --slice "07-04 13:49:29±120s"

Prints the raw records around a timestamp instead of writing outputs. Accepts s or m windows. Redacted by default, so slice output is safe to quote into an issue — and every map popup shows a copy-ready --slice string for the record it describes.


Output, and what is safe to share

file contents shareable?
digest.md the triage summary ✅ pseudonymized — the artifact to quote
digest.json same analysis, machine-readable ❌ full precision
aliases.local.json alias → real value mapping ❌ never leaves the machine
map.html interactive map ❌ full-precision coordinates
locations.geojson raw layer geometry ❌ full-precision coordinates

Redaction is pseudonymizing, not deleting: coordinates become COORD-A, fences GF-1, packages PKG-1, devices DEV-1, URLs URL-1. The same real value always gets the same alias, so the digest still reads as a coherent story — "the device left GF-1 at COORD-A" — while carrying nothing identifying.

digest.md and --slice output are the only artifacts meant to be pasted into a public issue. The map is a local instrument: it plots exactly where the device went.

If a log contains an auth token the SDK failed to redact, say "token present in log" — do not paste it.


The map

loganalyzer <file> --open

One self-contained HTML file: no CDN, no sibling assets, no build step. OpenStreetMap tiles are its only network dependency, so it works offline apart from the basemap and can be archived alongside a ticket.

  • Track — the route, with an optional color by speed mode
  • Fixes — chevrons pointing in the direction of travel (dot when course is unknown)
  • Layers — launch, lifecycle, errors, warnings, geofence, motion, HTTP, rejections, gaps, mock; high-volume layers start hidden
  • Time navigator — the strip along the bottom: an activity histogram over the whole capture with a window you can drag, stretch or zoom. Everything above filters to it, and the track is genuinely clipped, not just hidden.
  • Sessions — the ruler under the histogram. A capture is split into tracking sessions at silences in the location stream; click one to jump to it, or step with ‹ ›. Each reports its distance and what ended it (death, scheduler-window, suspension, wedge-candidate).
  • Popups — the record in its authored two-line shape, plus a copy-ready --slice

Markers use vendored Lucide icons, tinted semantically: green = tracking resumes / geofence ENTER, red = tracking parks / EXIT / failure, amber = DWELL / app foreground.


Customising the map

src/loganalyzer/vocabulary/map-rules.yaml decides which icon an event gets, which colour, which bearing from its anchor, and what is not worth mapping. Editing it changes the map; no Python change needed.

layers: is the single definition of every per-layer fact, and its key order is the layer order:

layers:
  geofence: { label: Geofence, kind: marker, glyph: "📢", icon: geofence, clock: 10 }

rules: are ordered (first match wins), scoped to a layer, and may be scoped to a platform with platform: android|ios. suppress: drops records from the map entirely, and each entry states why — so a later reader can judge whether it still holds.


How it works

sniff → records → segments → structs → classify → analyze → digest / map / geojson

classify joins each log line back to the SDK call site that emitted it, using a vocabulary harvested from the SDK sources across every release. That is how the tool recognizes lines it has never seen in a sample, and how it knows which SDK version a message belongs to.

src/loganalyzer/
  sniff.py      platform detection, gz/dup handling
  records.py    raw text → Records (folds continuation lines)
  segments.py   split at app-launch banners
  structs.py    extract locations, config, geofences, filter results
  classify.py   match records against the harvested vocabulary
  analyze.py    the findings: gaps, HTTP health, motion, power, anomalies
  locations.py  which coordinates are real fixes vs merely referenced
  sessions.py   tracking sessions (runs of fixes, split at 20-min silences)
  emit/         digest, geojson, map, navigator, icons
  vocabulary/   the harvested tables + map presentation rules

INTERFACES.md pins the contracts between these modules.

Tests

uv run pytest -q

The suite runs against real captures committed under tests/fixtures/ — real cadence, real gaps, real geofence chatter. Their coordinates have been moved by a single rigid transform, so every distance, speed, bearing and session boundary is exactly preserved while the route points somewhere nobody has been. A handful of tests are gated on captures that cannot be published and skip cleanly.

License

MIT — see LICENSE.

Release files for transistorsoft-loganalyzer 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for transistorsoft-loganalyzer 0.1.0
File Size Uploaded
transistorsoft_loganalyzer-0.1.0.tar.gz 327.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for transistorsoft-loganalyzer 0.1.0
File Interpreter ABI Platform
transistorsoft_loganalyzer-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 512.1 kB

Release files / transistorsoft_loganalyzer-0.1.0.tar.gz

Download URL transistorsoft_loganalyzer-0.1.0.tar.gz
Size 327.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e4f31fa5441f5a5fc29f2eab48ad7af73d407868c8db9daa086d020cd020511f
BLAKE2b-256 checksum
How to use checksums
9c266c5ed1be805a9a5d1fb1d5d80e32c6df59ebd1d8004f130abbc8492b8a9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release files / transistorsoft_loganalyzer-0.1.0-py3-none-any.whl

Download URL transistorsoft_loganalyzer-0.1.0-py3-none-any.whl
Size 184.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dda8942be78f3fb7844d78bc37f1e5fd0f2c4a0c51de1c463217f38df6af3b16
BLAKE2b-256 checksum
How to use checksums
83b7f96ad24558b816c1ab834860ea0ef323a033cb448e06ef99fe1d8d3f8285
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page