package current
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Pipeline language for keeping things up-to-date
Install
dune-project
Dependency
Authors
-
TThomas Leonard <talex5@gmail.com>
-
AAntonin Décimo <antonin@tarides.com>
-
TTim McGilchrist <timmcgil@gmail.com>
-
CCraig Ferguson <me@craigfe.io>
-
EEtienne MARAIS <etienne@maiste.fr>
-
AAnil Madhavapeddy <anil@recoil.org>
-
David Allsopp
-
EEwan Mellor <ewan@tarides.com>
-
KKate <kit.ty.kate@disroot.org>
-
MMark Elvers <mark.elvers@tunbury.org>
-
PPuneeth Chaganti <punchagan@muse-amuse.in>
-
LLucas Pluvinage <lucas@tarides.com>
-
NNavin Keswani <navin@novemberkilo.com>
-
TThomas Gazagnaire <thomas@gazagnaire.org>
-
Patrick Ferris
-
AArthur Wendling <art.wendling@gmail.com>
-
AAnurag Soni <anurag@sonianurag.com>
-
AAmbre Austen Suhamy <ambre@tarides.com>
-
BBen Andrew <benmandrew@gmail.com>
-
GGargi Sharma <gs051095@gmail.com>
-
JJonathan Coates <git@squiddev.cc>
-
JJules Aguillon <juloo.dsi@gmail.com>
-
MMagnus Skjegstad <magnus@skjegstad.com>
-
SShon Feder <shon.feder@gmail.com>
-
Ssmolck <46855713+smolck@users.noreply.github.com>
-
Ttatchi <corentin.leruth@gmail.com>
Maintainers
Sources
ocurrent-0.7.2.tbz
md5=19c8bdf96a8c5400322f32fe5784fb6b
sha512=7da7cbc7a909365a573e62641800050e263f309209d4339dab4a124934b13afe4b892fca4d424d79af539c6747bed31cfc7cad94dfb962e2d90366e0757083c3
doc/src/current/log_matcher.ml.html
Source file log_matcher.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154type rule = { pattern : string; report : string; score : int; } module Dao = struct type t = { db : Sqlite3.db; load : Sqlite3.stmt; add : Sqlite3.stmt; remove : Sqlite3.stmt; delete_all : Sqlite3.stmt; } let v = lazy ( let db = Lazy.force Db.v in Sqlite3.exec db "CREATE TABLE IF NOT EXISTS log_regexp ( \ re TEXT NOT NULL, \ report TEXT NOT NULL, \ score INTEGER NOT NULL, \ PRIMARY KEY (re))" |> Db.or_fail ~cmd:"create log_regexp"; let load = Sqlite3.prepare db "SELECT re, report, score FROM log_regexp ORDER BY score DESC, re" in let add = Sqlite3.prepare db "INSERT OR REPLACE INTO log_regexp (re, report, score) VALUES (?, ?, ?)" in let remove = Sqlite3.prepare db "DELETE FROM log_regexp WHERE re = ?" in let delete_all = Sqlite3.prepare db "DELETE FROM log_regexp" in { db; load; add; remove; delete_all } ) let load () = let t = Lazy.force v in Db.query t.load [] |> List.map @@ function | Sqlite3.Data.[ TEXT pattern; TEXT report; INT score ] -> { pattern; report; score = Int64.to_int score } | row -> Fmt.failwith "load: invalid row %a" Db.dump_row row let add { pattern; report; score } = let t = Lazy.force v in Db.exec t.add Sqlite3.Data.[ TEXT pattern; TEXT report; INT (Int64.of_int score) ] let remove pattern = let t = Lazy.force v in Db.exec t.remove Sqlite3.Data.[ TEXT pattern ]; match Sqlite3.changes t.db with | 0 -> Error `Rule_not_found | 1 -> Ok () | x -> Fmt.failwith "Multiple rows updated (%d)!" x let drop_all () = let t = Lazy.force v in Db.exec t.delete_all [] end type test = { re : Re.t; report : string; score : int; mark :Re.Mark.t; } type t = { tests : test list; combined : Re.re; } let re_subst = let (++) a b = Re.seq [a; b] in Re.(compile @@ char '\\' ++ group (rep1 digit)) let t = ref None let get () = match !t with | Some t -> t | None -> let raw = Dao.load () in let tests = raw |> List.filter_map (fun {pattern; report; score} -> try let mark, re = Re.Pcre.re pattern |> Re.mark in Some { re; report; mark; score } with ex -> Log.err (fun f -> f "Invalid pattern %S: %a" pattern Fmt.exn ex); None ) in let combined = Re.no_group (Re.alt (List.map (fun x -> x.re) tests)) |> Re.compile in let v = { tests; combined } in t := Some v; v let analyse_string ?job log_text = let t = get () in let did_header = ref false in Re.Seq.all t.combined log_text |> Seq.fold_left (fun best group -> (* For each match, find out which test matched. *) let matched = Re.Group.get group 0 in let test = List.find (fun test -> Re.Mark.test group test.mark) t.tests in job |> Option.iter (fun job -> if not !did_header then ( Job.log job "Log analysis:"; did_header := true ); Job.log job ">>> %s (score = %d)" matched test.score); match best with | Some (best_score, _, _) when best_score >= test.score -> best | _ -> Some (test.score, group, test) ) None |> function | None -> None (* No matches found *) | Some (_score, group, test) -> (* [test] is the best match. Run it again with matching to generate the report. *) let pos, stop = Re.Group.offset group 0 in let group = Re.exec ~pos ~len:(stop - pos) (Re.compile test.re) log_text in let subst g = let r = Re.Group.get g 1 in try Re.Group.get group (int_of_string r) with ex -> Log.err (fun f -> f "Bad group %S in report %S: %a" r test.report Fmt.exn ex); Fmt.str "Bad group %S in report %S: %a" r test.report Fmt.exn ex in let report = Re.replace ~all:true re_subst ~f:subst test.report in job |> Option.iter (fun job -> Job.log job "%s" report); Some report let analyse_file ?job log_path = let ch = open_in_bin (Fpath.to_string log_path) in (* re doesn't support streaming, so load the whole log at once. *) let log_text = Fun.protect (fun () -> really_input_string ch (in_channel_length ch)) ~finally:(fun () -> close_in ch) in analyse_string ?job log_text let analyse_job job = match Job.log_path (Job.id job) with | Error `Msg e -> Fmt.failwith "Job log missing! %s" e | Ok log_path -> analyse_file ~job log_path let add_rule rule = ignore (Re.Pcre.re rule.pattern); (* Check it compiles *) Dao.add rule; t := None let remove_rule pattern = Dao.remove pattern |> Stdlib.Result.map (fun () -> t := None) let list_rules () = Dao.load () let drop_all () = Dao.drop_all (); t := None
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>