Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions self-host/bootstrap/ir_driver.ir
Original file line number Diff line number Diff line change
Expand Up @@ -91687,6 +91687,11 @@ global ir_emitter_core_ir_active_generic_params list
global ir_emitter_core_ir_active_generic_concrete_types list
global ir_emitter_core_ir_active_generic_module_path str:m41s72
global ir_emitter_core_ir_current_arc_func str:m41s72
global ir_emitter_core_ALIGN_LEFT_BYTE 60
global ir_emitter_core_ALIGN_CENTER_BYTE 94
global ir_emitter_core_ALIGN_RIGHT_BYTE 62
global ir_emitter_core_FILL_ZERO_BYTE 48
global ir_emitter_core_FILL_SPACE_BYTE 32
global ir_emitter_core_ir_tail_match_node 0
func ir_emitter_core___init_globals_41 0 int
call 0 pith_map_new_default map 0
Expand Down Expand Up @@ -102410,7 +102415,7 @@ call 9 pith_cstring_eq bool 2 7 8
call 10 pith_cstring_release void 1 8
brif 9 L1050 L1051
label L1050
iconst 11 60
load 11 ir_emitter_core_ALIGN_LEFT_BYTE
load 12 c0
call 13 pith_cstring_release void 1 12
ret 11
Expand All @@ -102422,13 +102427,13 @@ call 16 pith_cstring_eq bool 2 14 15
call 17 pith_cstring_release void 1 15
brif 16 L1053 L1054
label L1053
iconst 18 94
load 18 ir_emitter_core_ALIGN_CENTER_BYTE
load 19 c0
call 20 pith_cstring_release void 1 19
ret 18
label L1054
label L1052
iconst 21 62
load 21 ir_emitter_core_ALIGN_RIGHT_BYTE
load 22 c0
call 23 pith_cstring_release void 1 22
ret 21
Expand Down Expand Up @@ -102484,13 +102489,13 @@ call 33 pith_cstring_release void 1 30
and 34 26 31
brif 34 L1059 L1060
label L1059
iconst 35 48
load 35 ir_emitter_core_FILL_ZERO_BYTE
load 36 c0
call 37 pith_cstring_release void 1 36
ret 35
label L1060
label L1058
iconst 38 32
load 38 ir_emitter_core_FILL_SPACE_BYTE
load 39 c0
call 40 pith_cstring_release void 1 39
ret 38
Expand Down
16 changes: 11 additions & 5 deletions self-host/ir_emitter_core.pith
Original file line number Diff line number Diff line change
Expand Up @@ -1483,22 +1483,28 @@ fn ir_interp_spec_precision(spec: String) -> Int:
i = i + 1
return p

ALIGN_LEFT_BYTE := 60 # '<'
ALIGN_CENTER_BYTE := 94 # '^'
ALIGN_RIGHT_BYTE := 62 # '>'
FILL_ZERO_BYTE := 48 # '0'
FILL_SPACE_BYTE := 32 # ' '

fn ir_interp_spec_align(spec: String) -> Int:
c0 := spec[0]
if c0 == "<":
return 60
return ALIGN_LEFT_BYTE
if c0 == "^":
return 94
return 62
return ALIGN_CENTER_BYTE
return ALIGN_RIGHT_BYTE

fn ir_interp_spec_fill(spec: String) -> Int:
mut i := 0
c0 := spec[0]
if c0 == "<" or c0 == ">" or c0 == "^":
i = 1
if i < spec.len() and spec[i] == "0":
return 48
return 32
return FILL_ZERO_BYTE
return FILL_SPACE_BYTE

fn ir_emit_interp_spec_part(node: Node) -> Int:
spec := node.value
Expand Down
37 changes: 13 additions & 24 deletions tools/logscan/logscan_lib.pith
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import std.compress.gzip as gzip
import std.data.table as table
import std.regex as regex

## one parsed access-log line.
# # one parsed access-log line.
pub struct Hit:
ip: String
stamp: String
Expand All @@ -18,8 +18,8 @@ pub struct Hit:
size: Int
millis: Int

## the whole analysis: parsed hits plus the derived aggregates the
## report and csv export read.
# # the whole analysis: parsed hits plus the derived aggregates the
# # report and csv export read.
pub struct Report:
total: Int
parse_errors: Int
Expand All @@ -33,19 +33,19 @@ pub struct Report:
# combined-log-ish format:
# 127.0.0.1 - - [06/Jul/2026:14:03:22] "GET /path HTTP/1.1" 200 512 45

## the line grammar as one pattern: ip, bracketed stamp, quoted
## request (method and path captured), then status, size, and millis.
# # the line grammar as one pattern: ip, bracketed stamp, quoted
# # request (method and path captured), then status, size, and millis.
pub fn line_pattern() -> Regex!:
q := chr(34)
return regex.compile("^([^ ]+) [^ ]+ [^ ]+ \\[([^\\]]+)\\] " + q + "([^ ]+) ([^ " + q + "]+)[^" + q + "]*" + q + " (\\d+) (\\d+) (\\d+)")

## parse one log line; none when the line is malformed.
# # parse one log line; none when the line is malformed.
pub fn parse_line(re: Regex, line: String) -> Hit?:
caps := re.captures(line)
if caps == none:
return none
if let c = caps:
status := parse_int(c[5]) catch -1
status := parse_int(c[5]) catch - 1
if status < 0:
return none
size := parse_int(c[6]) catch 0
Expand All @@ -71,8 +71,8 @@ fn hour_of(stamp: String) -> String:

# --- aggregation -------------------------------------------------------

## read a log (gzip-decompressed when the path ends in .gz) and fold
## every line into a report.
# # read a log (gzip-decompressed when the path ends in .gz) and fold
# # every line into a report.
pub fn analyze_file(path: String) -> Report!:
mut text := ""
if path.ends_with(".gz"):
Expand All @@ -82,7 +82,7 @@ pub fn analyze_file(path: String) -> Report!:
text = fs.read(path)!
return analyze_text(text)

## fold raw log text into a report.
# # fold raw log text into a report.
pub fn analyze_text(text: String) -> Report:
mut by_class: Map[String, Int] := {}
mut by_path_hits: Map[String, Int] := {}
Expand Down Expand Up @@ -129,7 +129,7 @@ fn top_paths(r: Report, n: Int) -> List[String]:

# --- output ------------------------------------------------------------

## the human-readable summary printed by the cli.
# # the human-readable summary printed by the cli.
pub fn render_report(r: Report) -> String:
nl := chr(10)
mut out := "requests: " + r.total.to_string() + " malformed: " + r.parse_errors.to_string() + " bytes: " + r.bytes_served.to_string() + nl
Expand All @@ -147,20 +147,9 @@ pub fn render_report(r: Report) -> String:
return out

fn sorted_keys(m: Map[String, Int]) -> List[String]:
mut ks: List[String] := []
for k in m.keys():
mut placed := false
mut i := 0
while i < ks.len() and not placed:
if k < ks[i]:
ks.insert(i, k)
placed = true
i = i + 1
if not placed:
ks.push(k)
return ks
return m.keys().sort()

## per-path stats as csv, via the data.table module.
# # per-path stats as csv, via the data.table module.
pub fn export_csv(r: Report) -> String:
mut rows: List[List[String]] := []
for p in top_paths(r, 1000000):
Expand Down
Loading