32.5 Reading a log
Each log has a page under Logs, with the Record and Statistics switches at the top and five views. Graphs, Entries and Analyse share one time range: a range ending now (5 minutes to 12 months), two moments you type in, or an interval you pick on a graph.
| View | What it shows |
|---|---|
| Graphs | Summary tiles and a graph per statistic. Click an interval to see its entries. Each graph downloads as CSV. |
| Entries | The entries of the range, with a search over all of them. Open an entry to see what was recorded around it. Download writes TSV, CSV or JSON lines. |
| Analyse | How one column's values are spread, read from the entries: percentiles and a histogram for numbers, the most common values for text, maps for positions (§32.8). It reads the newest 200,000 entries of the range by default. |
| Definition | The form, the JSON file, and C# code that records into the log. |
| Data | Try it out: record a test entry, or up to a million made-up ones, to see the graphs before the application records anything. Clean up: delete entries or statistics, rebuild the statistics, write to disk. The log's files, each with a download. |
The Entries search takes terms like these. All terms must match, and case is ignored unless you ask to match it:
timeout "timeout" anywhere in the entry
get*nodes * matches any run of characters, ? exactly one
"could not open" a phrase
error -shutdown "error" somewhere and "shutdown" nowhere
status:500 a term in one columnFrom code, db.CustomLogs.LogStore is the ILogStore behind the page, with the same reads:
using Relatude.DB.Logging.Statistics; // IntervalType
var store = db.CustomLogs.LogStore;
var to = DateTime.UtcNow;
var from = to.AddDays(-1);
// the newest 100 entries of the last day, and how many the range holds
var newest = store.ExtractLog("requests", from, to, skip: 0, take: 100, orderByDescendingDates: true, out var inRange);
// the same search as the Entries view
var failed = store.SearchLog("requests", "status:5??", from, to, 0, 100, true, out var failures);
// entries per hour
var perHour = store.AnalyseRows("requests", IntervalType.Hour, from, to, estimateNowInterval: false, fillInBlanks: true);
// distinct users per day, over 30 days
var users = store.AnalyseEstimatedUniqueCounts("requests", "user", IntervalType.Day, from.AddDays(-29), to, false, true);Nothing is indexed: a search reads every entry in its range, so the range sets the cost. Only the page you ask for is held in memory.