mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 18:14:11 +02:00
improve matching
This commit is contained in:
parent
04e391aea1
commit
9413b216ba
24 changed files with 73837 additions and 21689 deletions
535
Cargo.lock
generated
535
Cargo.lock
generated
|
|
@ -2,6 +2,23 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aes"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cipher",
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
|
|
@ -11,12 +28,89 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arbitrary"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
|
||||||
|
dependencies = [
|
||||||
|
"derive_arbitrary",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.16.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bzip2"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
|
||||||
|
dependencies = [
|
||||||
|
"bzip2-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bzip2-sys"
|
||||||
|
version = "0.1.11+1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
|
||||||
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cipher"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-common",
|
||||||
|
"inout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.1.3"
|
version = "4.1.3"
|
||||||
|
|
@ -60,17 +154,172 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"cloud-log-analyser-data",
|
"cloud-log-analyser-data",
|
||||||
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
|
"main_error",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
"zip",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloud-log-analyser-data"
|
name = "cloud-log-analyser-data"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "constant_time_eq"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc"
|
||||||
|
version = "3.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
|
||||||
|
dependencies = [
|
||||||
|
"crc-catalog",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc-catalog"
|
||||||
|
version = "2.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deflate64"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||||
|
dependencies = [
|
||||||
|
"powerfmt",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_arbitrary"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.71",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "displaydoc"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.71",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|
@ -83,6 +332,34 @@ version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inout"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is-terminal"
|
name = "is-terminal"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
|
|
@ -94,30 +371,85 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.11"
|
version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.155"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lockfree-object-pool"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.22"
|
version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lzma-rs"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"crc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "main_error"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "155db5e86c6e45ee456bf32fad5a290ee1f7151c2faca27ea27097568da67d1a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-conv"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
|
|
@ -130,6 +462,34 @@ version = "6.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pbkdf2"
|
||||||
|
version = "0.12.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"hmac",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pkg-config"
|
||||||
|
version = "0.3.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
|
@ -172,6 +532,36 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.5"
|
version = "1.10.5"
|
||||||
|
|
@ -238,12 +628,35 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-adler32"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "1.0.109"
|
||||||
|
|
@ -295,6 +708,31 @@ dependencies = [
|
||||||
"syn 2.0.71",
|
"syn 2.0.71",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"num-conv",
|
||||||
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
|
|
@ -307,6 +745,12 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
|
|
@ -388,3 +832,94 @@ name = "windows_x86_64_msvc"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize_derive"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.71",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zip"
|
||||||
|
version = "2.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b895748a3ebcb69b9d38dcfdf21760859a4b0d0b0015277640c2ef4c69640e6f"
|
||||||
|
dependencies = [
|
||||||
|
"aes",
|
||||||
|
"arbitrary",
|
||||||
|
"bzip2",
|
||||||
|
"constant_time_eq",
|
||||||
|
"crc32fast",
|
||||||
|
"crossbeam-utils",
|
||||||
|
"deflate64",
|
||||||
|
"displaydoc",
|
||||||
|
"flate2",
|
||||||
|
"hmac",
|
||||||
|
"indexmap",
|
||||||
|
"lzma-rs",
|
||||||
|
"memchr",
|
||||||
|
"pbkdf2",
|
||||||
|
"rand",
|
||||||
|
"sha1",
|
||||||
|
"thiserror",
|
||||||
|
"time",
|
||||||
|
"zeroize",
|
||||||
|
"zopfli",
|
||||||
|
"zstd",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zopfli"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"crc32fast",
|
||||||
|
"lockfree-object-pool",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-safe",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-safe"
|
||||||
|
version = "7.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-sys"
|
||||||
|
version = "2.0.12+zstd.1.5.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
main_error = "0.1.2"
|
||||||
thiserror = "1.0.63"
|
thiserror = "1.0.63"
|
||||||
serde = { version = "1.0.204", features = ["derive"] }
|
serde = { version = "1.0.204", features = ["derive"] }
|
||||||
serde_json = "1.0.120"
|
serde_json = "1.0.120"
|
||||||
|
|
@ -11,6 +12,8 @@ regex = "1.10.5"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
clap = { version = "=4.1.3", features = ["derive"] }
|
clap = { version = "=4.1.3", features = ["derive"] }
|
||||||
cloud-log-analyser-data = { version = "0.1.0", path = "./data" }
|
cloud-log-analyser-data = { version = "0.1.0", path = "./data" }
|
||||||
|
zip = "2.1.5"
|
||||||
|
itertools = "0.13.0"
|
||||||
|
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
@ -5,6 +5,9 @@ mod server_27;
|
||||||
mod server_28;
|
mod server_28;
|
||||||
mod server_29;
|
mod server_29;
|
||||||
|
|
||||||
|
pub const MIN_VERSION: u32 = 24;
|
||||||
|
pub const MAX_VERSION: u32 = 29;
|
||||||
|
|
||||||
pub fn get_statements(name: &str, version: u32) -> &[crate::LoggingStatement] {
|
pub fn get_statements(name: &str, version: u32) -> &[crate::LoggingStatement] {
|
||||||
match (name, version) {
|
match (name, version) {
|
||||||
("server", 24) => server_24::STATEMENTS,
|
("server", 24) => server_24::STATEMENTS,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
||||||
mod data;
|
mod data;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
pub use data::get_statements;
|
pub use data::{get_statements, MAX_VERSION, MIN_VERSION};
|
||||||
pub use types::*;
|
pub use types::*;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Clone, Copy)]
|
#[derive(Debug, Default, PartialEq, Clone, Copy)]
|
||||||
pub enum LogLevel {
|
pub enum LogLevel {
|
||||||
Debug,
|
Debug,
|
||||||
|
|
@ -32,5 +34,36 @@ pub struct LoggingStatement {
|
||||||
pub path: &'static str,
|
pub path: &'static str,
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
pub placeholders: &'static [&'static str],
|
pub placeholders: &'static [&'static str],
|
||||||
|
pub has_meaningful_message: bool,
|
||||||
|
pub exception: Option<&'static str>,
|
||||||
pub regex: &'static str,
|
pub regex: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LoggingStatement {
|
||||||
|
pub fn message(&self) -> impl Display + '_ {
|
||||||
|
LoggingMessage { message: &self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LoggingMessage<'a> {
|
||||||
|
message: &'a LoggingStatement,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for LoggingMessage<'a> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if self.message.regex.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let mut placeholder_index = 0;
|
||||||
|
let regex = &self.message.regex[1..self.message.regex.len() - 1];
|
||||||
|
for part in regex.split("(.*)") {
|
||||||
|
write!(f, "{part}")?;
|
||||||
|
if let Some(placeholder) = self.message.placeholders.get(placeholder_index) {
|
||||||
|
write!(f, "{placeholder}")?;
|
||||||
|
}
|
||||||
|
placeholder_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@
|
||||||
releaseMatrix = buildMatrix releaseTargets;
|
releaseMatrix = buildMatrix releaseTargets;
|
||||||
|
|
||||||
devShells.default = mkShell {
|
devShells.default = mkShell {
|
||||||
nativeBuildInputs = with pkgs; [cargo rustc bacon cargo-msrv cargo-insta];
|
nativeBuildInputs = with pkgs; [cargo rustc bacon cargo-msrv cargo-insta clippy];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,12 @@ pub struct LoggingStatement<'a> {
|
||||||
pub path: &'a str,
|
pub path: &'a str,
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
pub placeholders: &'a [&'a str],
|
pub placeholders: &'a [&'a str],
|
||||||
|
pub has_meaningful_message: bool,
|
||||||
|
pub exception: Option<&'a str>,
|
||||||
pub regex: &'a str,
|
pub regex: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_pattern<'a>(parts: &[crate::MessagePart]) -> String {
|
fn build_pattern(parts: &[crate::MessagePart]) -> String {
|
||||||
let mut pattern = String::with_capacity(128);
|
let mut pattern = String::with_capacity(128);
|
||||||
pattern.push('^');
|
pattern.push('^');
|
||||||
for part in parts {
|
for part in parts {
|
||||||
|
|
@ -74,6 +76,8 @@ pub fn bake_statement(output: &mut String, statement: &crate::LoggingStatement)
|
||||||
level: statement.level.into(),
|
level: statement.level.into(),
|
||||||
path: statement.path,
|
path: statement.path,
|
||||||
line: statement.line,
|
line: statement.line,
|
||||||
|
has_meaningful_message: statement.has_meaningful_message,
|
||||||
|
exception: statement.exception.as_deref(),
|
||||||
placeholders: &placeholders,
|
placeholders: &placeholders,
|
||||||
regex: &pattern,
|
regex: &pattern,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::string::{unescape, DoubleQuoteString, SingleQuoteString};
|
use crate::messagebuilder::MessageBuilder;
|
||||||
use crate::{LogLevel, LoggingStatement, MessagePart};
|
use crate::{LogLevel, LoggingStatement};
|
||||||
use tree_sitter::{Language, Node, Parser, Query, QueryCursor};
|
use tree_sitter::{Language, Node, Parser, Query, QueryCursor};
|
||||||
|
|
||||||
pub struct LogExtractor {
|
pub struct LogExtractor {
|
||||||
|
|
@ -15,7 +15,7 @@ impl LogExtractor {
|
||||||
&language,
|
&language,
|
||||||
r#"(member_call_expression
|
r#"(member_call_expression
|
||||||
name: (name)@name
|
name: (name)@name
|
||||||
arguments: (arguments ((argument)+ @arg))
|
arguments: (arguments) @args
|
||||||
)"#,
|
)"#,
|
||||||
)
|
)
|
||||||
.expect("invalid query");
|
.expect("invalid query");
|
||||||
|
|
@ -23,7 +23,8 @@ impl LogExtractor {
|
||||||
&language,
|
&language,
|
||||||
r#"(throw_expression
|
r#"(throw_expression
|
||||||
(object_creation_expression
|
(object_creation_expression
|
||||||
(arguments ((argument)+ @arg))
|
[(name) (qualified_name)] @name
|
||||||
|
(arguments) @args
|
||||||
)
|
)
|
||||||
)"#,
|
)"#,
|
||||||
)
|
)
|
||||||
|
|
@ -51,52 +52,25 @@ impl LogExtractor {
|
||||||
|
|
||||||
let mut log_call_cursor = QueryCursor::new();
|
let mut log_call_cursor = QueryCursor::new();
|
||||||
let mut throw_call_cursor = QueryCursor::new();
|
let mut throw_call_cursor = QueryCursor::new();
|
||||||
let mut tree_cursor = tree.walk();
|
|
||||||
let log_calls = self.get_log_calls(&mut log_call_cursor, code, tree.root_node());
|
let log_calls = self.get_log_calls(&mut log_call_cursor, code, tree.root_node());
|
||||||
let throw_calls = self.get_throw_calls(&mut throw_call_cursor, code, tree.root_node());
|
let throw_calls = self.get_throw_calls(&mut throw_call_cursor, code, tree.root_node());
|
||||||
let mut all = log_calls
|
let mut all = log_calls
|
||||||
.chain(throw_calls)
|
.chain(throw_calls)
|
||||||
.filter_map(|call| {
|
.filter_map(|call| {
|
||||||
let argument = call.arguments.child(0)?;
|
let mut message_builder = MessageBuilder::with_capacity(16);
|
||||||
if argument.grammar_name() != "string"
|
|
||||||
&& argument.grammar_name() != "encapsed_string"
|
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let mut argument_string_parts = argument.children(&mut tree_cursor);
|
|
||||||
let is_double_quote = argument_string_parts.next()?.grammar_name() == r#"""#;
|
|
||||||
let mut message_builder =
|
|
||||||
MessageBuilder::with_capacity(argument_string_parts.len());
|
|
||||||
|
|
||||||
for string_part in argument_string_parts {
|
if let Some(argument) = call.arguments {
|
||||||
match string_part.grammar_name() {
|
let argument = argument.child(0)?;
|
||||||
"string_content" => {
|
message_builder.push_node(argument, code);
|
||||||
let content = string_part.utf8_text(code.as_bytes()).unwrap();
|
|
||||||
message_builder.push_literal(content);
|
|
||||||
}
|
|
||||||
"escape_sequence" => {
|
|
||||||
let raw = string_part.utf8_text(code.as_bytes()).unwrap();
|
|
||||||
let content = if is_double_quote {
|
|
||||||
unescape::<DoubleQuoteString>(raw)
|
|
||||||
} else {
|
|
||||||
unescape::<SingleQuoteString>(raw)
|
|
||||||
}
|
|
||||||
.unwrap();
|
|
||||||
message_builder.push_literal(&content);
|
|
||||||
}
|
|
||||||
r#"'"# | r#"""# | r#"{"# | r#"}"# => {}
|
|
||||||
_ => {
|
|
||||||
let placeholder = string_part.utf8_text(code.as_bytes()).unwrap();
|
|
||||||
message_builder.push_placeholder(placeholder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(LoggingStatement {
|
Some(LoggingStatement {
|
||||||
level: call.level,
|
level: call.level,
|
||||||
line: call.line + 1,
|
line: call.line + 1,
|
||||||
path,
|
path,
|
||||||
message_parts: message_builder.0,
|
has_meaningful_message: message_builder.is_meaningful(),
|
||||||
|
exception: call.exception,
|
||||||
|
message_parts: message_builder.into(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
@ -120,11 +94,13 @@ impl LogExtractor {
|
||||||
.unwrap_or("malformed utf8");
|
.unwrap_or("malformed utf8");
|
||||||
let level = LogLevel::parse(name)?;
|
let level = LogLevel::parse(name)?;
|
||||||
let line = method_call.captures[0].node.start_position().row;
|
let line = method_call.captures[0].node.start_position().row;
|
||||||
|
|
||||||
let arguments = method_call.captures[1].node;
|
let arguments = method_call.captures[1].node;
|
||||||
Some(LogCall {
|
Some(LogCall {
|
||||||
level,
|
level,
|
||||||
line,
|
line,
|
||||||
arguments,
|
arguments: arguments.named_child(0),
|
||||||
|
exception: None,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -137,15 +113,22 @@ impl LogExtractor {
|
||||||
) -> impl Iterator<Item = LogCall> + 'a {
|
) -> impl Iterator<Item = LogCall> + 'a {
|
||||||
let throws = cursor.matches(&self.throw_query, node, code.as_bytes());
|
let throws = cursor.matches(&self.throw_query, node, code.as_bytes());
|
||||||
|
|
||||||
throws.filter_map(|method_call| {
|
throws.map(|method_call| {
|
||||||
let level = LogLevel::Exception;
|
let level = LogLevel::Exception;
|
||||||
let arguments = method_call.captures[0].node;
|
let arguments = method_call.captures[1].node;
|
||||||
let line = arguments.start_position().row;
|
let line = arguments.start_position().row;
|
||||||
Some(LogCall {
|
LogCall {
|
||||||
level,
|
level,
|
||||||
line,
|
line,
|
||||||
arguments,
|
arguments: arguments.named_child(0),
|
||||||
})
|
exception: Some(
|
||||||
|
method_call.captures[0]
|
||||||
|
.node
|
||||||
|
.utf8_text(code.as_bytes())
|
||||||
|
.unwrap()
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -159,36 +142,21 @@ impl Default for LogExtractor {
|
||||||
struct LogCall<'tree> {
|
struct LogCall<'tree> {
|
||||||
level: LogLevel,
|
level: LogLevel,
|
||||||
line: usize,
|
line: usize,
|
||||||
arguments: Node<'tree>,
|
exception: Option<String>,
|
||||||
}
|
arguments: Option<Node<'tree>>,
|
||||||
|
|
||||||
struct MessageBuilder(Vec<MessagePart>);
|
|
||||||
|
|
||||||
impl MessageBuilder {
|
|
||||||
pub fn with_capacity(cap: usize) -> Self {
|
|
||||||
MessageBuilder(Vec::with_capacity(cap))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_literal(&mut self, content: &str) {
|
|
||||||
if let Some(MessagePart::Literal(last_part)) = self.0.last_mut() {
|
|
||||||
last_part.push_str(content);
|
|
||||||
} else {
|
|
||||||
self.0.push(MessagePart::Literal(content.into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_placeholder(&mut self, placeholder: &str) {
|
|
||||||
self.0.push(MessagePart::PlaceHolder(placeholder.into()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract_logging() {
|
fn test_extract_logging() {
|
||||||
|
use crate::MessagePart;
|
||||||
|
|
||||||
let code = r#"<?php
|
let code = r#"<?php
|
||||||
function test() {
|
function test() {
|
||||||
$this->logger->warning("failed to find trash item for $rootTrashedItemName deleted at $rootTrashedItemDate in folder $groupFolderId", ['app' => 'groupfolders']);
|
$this->logger->warning("failed to find trash item for $rootTrashedItemName deleted at $rootTrashedItemDate in folder $groupFolderId", ['app' => 'groupfolders']);
|
||||||
$logger->info('foobar');
|
$logger->info('foobar');
|
||||||
throw new FooException("foo \"bar\" \' {$this->blarg}");
|
throw new FooException("foo \"bar\" \' {$this->blarg}");
|
||||||
|
throw new BarException();
|
||||||
|
$this->logger->error('Share notification mail could not be sent to: ' . implode(', ', $failedRecipients));
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
"#;
|
"#;
|
||||||
|
|
@ -200,6 +168,8 @@ fn test_extract_logging() {
|
||||||
path: "foo.php",
|
path: "foo.php",
|
||||||
line: 3,
|
line: 3,
|
||||||
level: LogLevel::Warn,
|
level: LogLevel::Warn,
|
||||||
|
has_meaningful_message: true,
|
||||||
|
exception: None,
|
||||||
message_parts: vec![
|
message_parts: vec![
|
||||||
MessagePart::Literal("failed to find trash item for ".into()),
|
MessagePart::Literal("failed to find trash item for ".into()),
|
||||||
MessagePart::PlaceHolder("$rootTrashedItemName".into()),
|
MessagePart::PlaceHolder("$rootTrashedItemName".into()),
|
||||||
|
|
@ -216,6 +186,8 @@ fn test_extract_logging() {
|
||||||
path: "foo.php",
|
path: "foo.php",
|
||||||
line: 4,
|
line: 4,
|
||||||
level: LogLevel::Info,
|
level: LogLevel::Info,
|
||||||
|
has_meaningful_message: true,
|
||||||
|
exception: None,
|
||||||
message_parts: vec![MessagePart::Literal("foobar".into())]
|
message_parts: vec![MessagePart::Literal("foobar".into())]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
@ -225,10 +197,37 @@ fn test_extract_logging() {
|
||||||
path: "foo.php",
|
path: "foo.php",
|
||||||
line: 5,
|
line: 5,
|
||||||
level: LogLevel::Exception,
|
level: LogLevel::Exception,
|
||||||
|
has_meaningful_message: true,
|
||||||
|
exception: Some("FooException".into()),
|
||||||
message_parts: vec![
|
message_parts: vec![
|
||||||
MessagePart::Literal(r#"foo "bar" \' "#.into()),
|
MessagePart::Literal(r#"foo "bar" \' "#.into()),
|
||||||
MessagePart::PlaceHolder("$this->blarg".into())
|
MessagePart::PlaceHolder("$this->blarg".into())
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
logs[3],
|
||||||
|
LoggingStatement {
|
||||||
|
path: "foo.php",
|
||||||
|
line: 6,
|
||||||
|
level: LogLevel::Exception,
|
||||||
|
has_meaningful_message: false,
|
||||||
|
exception: Some("BarException".into()),
|
||||||
|
message_parts: vec![]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
logs[4],
|
||||||
|
LoggingStatement {
|
||||||
|
path: "foo.php",
|
||||||
|
line: 7,
|
||||||
|
level: LogLevel::Error,
|
||||||
|
has_meaningful_message: true,
|
||||||
|
exception: None,
|
||||||
|
message_parts: vec![
|
||||||
|
MessagePart::Literal("Share notification mail could not be sent to: ".into()),
|
||||||
|
MessagePart::PlaceHolder("implode(', ', $failedRecipients)".into())
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ impl LogLevel {
|
||||||
"emergency" => Some(LogLevel::Emergency),
|
"emergency" => Some(LogLevel::Emergency),
|
||||||
"exception" => Some(LogLevel::Exception),
|
"exception" => Some(LogLevel::Exception),
|
||||||
"log" => Some(LogLevel::Unknown),
|
"log" => Some(LogLevel::Unknown),
|
||||||
|
"printErrorPage" => Some(LogLevel::Unknown),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ mod bake;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod extractor;
|
pub mod extractor;
|
||||||
mod level;
|
mod level;
|
||||||
|
mod messagebuilder;
|
||||||
pub mod string;
|
pub mod string;
|
||||||
|
|
||||||
use crate::bake::bake_statement;
|
use crate::bake::bake_statement;
|
||||||
|
|
@ -20,6 +21,8 @@ pub struct LoggingStatement<'a> {
|
||||||
level: LogLevel,
|
level: LogLevel,
|
||||||
path: &'a str,
|
path: &'a str,
|
||||||
line: usize,
|
line: usize,
|
||||||
|
has_meaningful_message: bool,
|
||||||
|
exception: Option<String>,
|
||||||
message_parts: Vec<MessagePart>,
|
message_parts: Vec<MessagePart>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
91
logging-extractor/src/messagebuilder.rs
Normal file
91
logging-extractor/src/messagebuilder.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
use crate::string::{unescape, DoubleQuoteString, SingleQuoteString};
|
||||||
|
use crate::MessagePart;
|
||||||
|
use tree_sitter::Node;
|
||||||
|
|
||||||
|
pub struct MessageBuilder {
|
||||||
|
pub parts: Vec<MessagePart>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MessageBuilder {
|
||||||
|
pub fn with_capacity(cap: usize) -> Self {
|
||||||
|
MessageBuilder {
|
||||||
|
parts: Vec::with_capacity(cap),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_literal(&mut self, content: &str) {
|
||||||
|
if let Some(MessagePart::Literal(last_part)) = self.parts.last_mut() {
|
||||||
|
last_part.push_str(content);
|
||||||
|
} else {
|
||||||
|
self.parts.push(MessagePart::Literal(content.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_placeholder(&mut self, placeholder: &str) {
|
||||||
|
self.parts
|
||||||
|
.push(MessagePart::PlaceHolder(placeholder.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_node(&mut self, node: Node, code: &str) {
|
||||||
|
let mut cursor = node.walk();
|
||||||
|
match node.grammar_name() {
|
||||||
|
"string" | "encapsed_string" => {
|
||||||
|
let mut argument_string_parts = node.children(&mut cursor);
|
||||||
|
let is_double_quote = argument_string_parts
|
||||||
|
.next()
|
||||||
|
.map(|child| child.grammar_name())
|
||||||
|
.unwrap_or_default()
|
||||||
|
== r#"""#;
|
||||||
|
|
||||||
|
for string_part in argument_string_parts {
|
||||||
|
match string_part.grammar_name() {
|
||||||
|
"string_content" => {
|
||||||
|
let content = string_part.utf8_text(code.as_bytes()).unwrap();
|
||||||
|
self.push_literal(content);
|
||||||
|
}
|
||||||
|
"escape_sequence" => {
|
||||||
|
let raw = string_part.utf8_text(code.as_bytes()).unwrap();
|
||||||
|
let content = if is_double_quote {
|
||||||
|
unescape::<DoubleQuoteString>(raw)
|
||||||
|
} else {
|
||||||
|
unescape::<SingleQuoteString>(raw)
|
||||||
|
}
|
||||||
|
.unwrap();
|
||||||
|
self.push_literal(&content);
|
||||||
|
}
|
||||||
|
r#"'"# | r#"""# | r#"{"# | r#"}"# => {}
|
||||||
|
_ => {
|
||||||
|
let placeholder = string_part.utf8_text(code.as_bytes()).unwrap();
|
||||||
|
self.push_placeholder(placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"binary_expression" => {
|
||||||
|
let start = node.named_child(0).unwrap().range().end_byte;
|
||||||
|
let end = node.named_child(1).unwrap().range().start_byte;
|
||||||
|
let operator = &code[start..end];
|
||||||
|
if operator.trim() == "." {
|
||||||
|
for part in node.named_children(&mut cursor) {
|
||||||
|
self.push_node(part, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let placeholder = node.utf8_text(code.as_bytes()).unwrap();
|
||||||
|
self.push_placeholder(placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure there is at least some text to match
|
||||||
|
pub fn is_meaningful(&self) -> bool {
|
||||||
|
self.parts.iter().any(|part| matches!(part, MessagePart::Literal(part) if part.contains(|c: char| c.is_ascii_alphanumeric())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MessageBuilder> for Vec<MessagePart> {
|
||||||
|
fn from(value: MessageBuilder) -> Self {
|
||||||
|
value.parts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -217,6 +217,7 @@ pub fn is_array_key_numeric(string: &str) -> bool {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
#![allow(clippy::needless_raw_string_hashes)]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,38 @@ expression: output
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 129,
|
"line": 129,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "\\Exception",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "invalid share type!"
|
"Literal": "invalid share type!"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"level": "exception",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 305,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "ProviderException",
|
||||||
|
"message_parts": [
|
||||||
|
{
|
||||||
|
"Literal": "Group \""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PlaceHolder": "$share->getSharedWith()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Literal": "\" does not exist"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 309,
|
"line": 309,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "ProviderException",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "Recipient not in receiving group"
|
"Literal": "Recipient not in receiving group"
|
||||||
|
|
@ -27,6 +49,8 @@ expression: output
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 339,
|
"line": 339,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "ProviderException",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "Recipient does not match"
|
"Literal": "Recipient does not match"
|
||||||
|
|
@ -37,16 +61,38 @@ expression: output
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 344,
|
"line": 344,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "ProviderException",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "Invalid shareType"
|
"Literal": "Invalid shareType"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"level": "exception",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 431,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "ProviderException",
|
||||||
|
"message_parts": [
|
||||||
|
{
|
||||||
|
"Literal": "Group \""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PlaceHolder": "$share->getSharedWith()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Literal": "\" does not exist"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 476,
|
"line": 476,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "ProviderException",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "Recipient does not match"
|
"Literal": "Recipient does not match"
|
||||||
|
|
@ -57,6 +103,8 @@ expression: output
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 482,
|
"line": 482,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "ProviderException",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "Invalid shareType"
|
"Literal": "Invalid shareType"
|
||||||
|
|
@ -67,30 +115,155 @@ expression: output
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 609,
|
"line": 609,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "\\Exception",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "non-shallow getSharesInFolder is no longer supported"
|
"Literal": "non-shallow getSharesInFolder is no longer supported"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"level": "exception",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 763,
|
||||||
|
"has_meaningful_message": false,
|
||||||
|
"exception": "ShareNotFound",
|
||||||
|
"message_parts": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "exception",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 769,
|
||||||
|
"has_meaningful_message": false,
|
||||||
|
"exception": "ShareNotFound",
|
||||||
|
"message_parts": []
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"level": "exception",
|
"level": "exception",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 963,
|
"line": 963,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": "BackendError",
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "Invalid backend"
|
"Literal": "Invalid backend"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"level": "exception",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 993,
|
||||||
|
"has_meaningful_message": false,
|
||||||
|
"exception": "ShareNotFound",
|
||||||
|
"message_parts": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "exception",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 999,
|
||||||
|
"has_meaningful_message": false,
|
||||||
|
"exception": "ShareNotFound",
|
||||||
|
"message_parts": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "error",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 1171,
|
||||||
|
"has_meaningful_message": false,
|
||||||
|
"exception": null,
|
||||||
|
"message_parts": [
|
||||||
|
{
|
||||||
|
"PlaceHolder": "$e->getMessage()"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "debug",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 1392,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": null,
|
||||||
|
"message_parts": [
|
||||||
|
{
|
||||||
|
"Literal": "Share notification not sent to "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PlaceHolder": "$share->getSharedWith()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Literal": " because user could not be found."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "debug",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 1401,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": null,
|
||||||
|
"message_parts": [
|
||||||
|
{
|
||||||
|
"Literal": "Share notification not sent to "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PlaceHolder": "$share->getSharedWith()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Literal": " because email address is not set."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "debug",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 1416,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": null,
|
||||||
|
"message_parts": [
|
||||||
|
{
|
||||||
|
"Literal": "Sent share notification to "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PlaceHolder": "$emailAddress"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Literal": " for share with ID "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PlaceHolder": "$share->getId()"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Literal": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"level": "error",
|
"level": "error",
|
||||||
"path": "/DefaultShareProvider.php",
|
"path": "/DefaultShareProvider.php",
|
||||||
"line": 1420,
|
"line": 1420,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": null,
|
||||||
"message_parts": [
|
"message_parts": [
|
||||||
{
|
{
|
||||||
"Literal": "Share notification mail could not be sent."
|
"Literal": "Share notification mail could not be sent."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level": "error",
|
||||||
|
"path": "/DefaultShareProvider.php",
|
||||||
|
"line": 1507,
|
||||||
|
"has_meaningful_message": true,
|
||||||
|
"exception": null,
|
||||||
|
"message_parts": [
|
||||||
|
{
|
||||||
|
"Literal": "Share notification mail could not be sent to: "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PlaceHolder": "implode(', ', $failedRecipients)"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
20
src/error.rs
Normal file
20
src/error.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
use zip::result::ZipError;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LogError {
|
||||||
|
#[error("Error while reading input file '{path}': {err:#}")]
|
||||||
|
Read { err: ReadError, path: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum ReadError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
|
Zip(#[from] ZipError),
|
||||||
|
#[error("archive contains multiple files")]
|
||||||
|
MultipleFiles,
|
||||||
|
#[error("archive contains no files")]
|
||||||
|
NoFiles,
|
||||||
|
}
|
||||||
40
src/logfile.rs
Normal file
40
src/logfile.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
use crate::error::ReadError;
|
||||||
|
use itertools::Either;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
use zip::ZipArchive;
|
||||||
|
|
||||||
|
pub enum LogFile {
|
||||||
|
Plain(BufReader<File>),
|
||||||
|
Zip(ZipArchive<File>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogFile {
|
||||||
|
pub fn open(path: &str) -> Result<LogFile, ReadError> {
|
||||||
|
let file = File::open(path)?;
|
||||||
|
if path.ends_with(".zip") {
|
||||||
|
let mut zip = ZipArchive::new(file)?;
|
||||||
|
if zip.len() > 1 {
|
||||||
|
return Err(ReadError::MultipleFiles);
|
||||||
|
} else if zip.is_empty() {
|
||||||
|
return Err(ReadError::NoFiles);
|
||||||
|
}
|
||||||
|
// ensure we can open the file
|
||||||
|
let _ = zip.by_index(0)?;
|
||||||
|
|
||||||
|
Ok(LogFile::Zip(zip))
|
||||||
|
} else {
|
||||||
|
Ok(LogFile::Plain(BufReader::new(file)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&mut self) -> impl Iterator<Item = String> + '_ {
|
||||||
|
match self {
|
||||||
|
LogFile::Plain(file) => Either::Left(file.lines().flatten()),
|
||||||
|
LogFile::Zip(zip) => {
|
||||||
|
let file = zip.by_index(0).expect("failed to open zip content again");
|
||||||
|
Either::Right(BufReader::new(file).lines().flatten())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/logline.rs
Normal file
20
src/logline.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use serde::Deserialize;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct LogLine<'a> {
|
||||||
|
pub version: &'a str,
|
||||||
|
pub level: i64,
|
||||||
|
pub message: Cow<'a, str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LogLine<'_> {
|
||||||
|
pub fn major_version(&self) -> Option<u32> {
|
||||||
|
let major = self
|
||||||
|
.version
|
||||||
|
.split_once('.')
|
||||||
|
.map(|(major, _)| major)
|
||||||
|
.unwrap_or(self.version);
|
||||||
|
major.parse().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
136
src/main.rs
136
src/main.rs
|
|
@ -1,97 +1,81 @@
|
||||||
|
use crate::error::LogError;
|
||||||
|
use crate::logfile::LogFile;
|
||||||
|
use crate::logline::LogLine;
|
||||||
use crate::matcher::Matcher;
|
use crate::matcher::Matcher;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use cloud_log_analyser_data::get_statements;
|
use cloud_log_analyser_data::{get_statements, MAX_VERSION};
|
||||||
use serde::Deserialize;
|
use main_error::MainResult;
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
|
mod error;
|
||||||
|
mod logfile;
|
||||||
|
mod logline;
|
||||||
mod matcher;
|
mod matcher;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
enum Args {
|
struct Args {
|
||||||
Log(LogCommand),
|
|
||||||
File(FileCommand),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
|
||||||
struct LogCommand {
|
|
||||||
line: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
|
||||||
struct FileCommand {
|
|
||||||
file: String,
|
file: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
fn main() -> MainResult {
|
||||||
struct LogLine<'a> {
|
|
||||||
version: &'a str,
|
|
||||||
level: i64,
|
|
||||||
message: Cow<'a, str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
match args {
|
let mut log_file = LogFile::open(&args.file).map_err(|err| LogError::Read {
|
||||||
Args::Log(LogCommand { line }) => {
|
err,
|
||||||
let parsed_line: LogLine = serde_json::from_str(&line).unwrap();
|
path: args.file,
|
||||||
let major = parsed_line.version.split(".").next().unwrap();
|
})?;
|
||||||
let major = major.parse().unwrap();
|
let mut lines = log_file.iter();
|
||||||
let statements = get_statements("server", major);
|
|
||||||
let matcher = Matcher::new(statements);
|
|
||||||
let index = matcher.match_log(parsed_line.level.into(), parsed_line.message.as_ref());
|
|
||||||
if let Some(index) = index {
|
|
||||||
let statement = &statements[index];
|
|
||||||
println!("match found: {} line {}", statement.path, statement.line);
|
|
||||||
} else {
|
|
||||||
eprintln!("No match found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Args::File(FileCommand { file }) => {
|
|
||||||
let file = BufReader::new(File::open(file).unwrap());
|
|
||||||
let mut counts: HashMap<usize, usize> = HashMap::default();
|
|
||||||
let mut lines = file.lines().flatten();
|
|
||||||
let first = lines.next().unwrap();
|
|
||||||
let first_parsed: LogLine = serde_json::from_str(&first).unwrap();
|
|
||||||
|
|
||||||
let major = first_parsed.version.split(".").next().unwrap();
|
let mut counts: HashMap<usize, usize> = HashMap::new();
|
||||||
let major = major.parse().unwrap();
|
let first = lines.next().unwrap();
|
||||||
let statements = get_statements("server", major);
|
let first_parsed: LogLine = serde_json::from_str(&first).unwrap();
|
||||||
let matcher = Matcher::new(statements);
|
|
||||||
|
|
||||||
let lines = once(first).chain(lines);
|
let statements = get_statements(
|
||||||
let mut error_count = 0;
|
"server",
|
||||||
for line in lines {
|
first_parsed.major_version().unwrap_or(MAX_VERSION),
|
||||||
if line.starts_with('{') {
|
);
|
||||||
let parsed = match serde_json::from_str::<LogLine>(&line) {
|
let matcher = Matcher::new(statements);
|
||||||
Ok(parsed) => parsed,
|
|
||||||
Err(_) => {
|
let lines = once(first).chain(lines);
|
||||||
error_count += 1;
|
let mut error_count = 0;
|
||||||
continue;
|
let mut unmatched = 0;
|
||||||
}
|
for line in lines {
|
||||||
};
|
if line.starts_with('{') {
|
||||||
if let Some(index) =
|
let parsed = match serde_json::from_str::<LogLine>(&line) {
|
||||||
matcher.match_log(parsed.level.into(), parsed.message.as_ref())
|
Ok(parsed) => parsed,
|
||||||
{
|
Err(_) => {
|
||||||
counts.entry(index).or_default().add_assign(1);
|
error_count += 1;
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
let mut counts: Vec<(_, _)> = counts.into_iter().collect();
|
if let Some(index) = matcher.match_log(parsed.level.into(), parsed.message.as_ref()) {
|
||||||
counts.sort_by_key(|(_, count)| *count);
|
counts.entry(index).or_default().add_assign(1);
|
||||||
counts.reverse();
|
} else {
|
||||||
for (index, count) in counts {
|
unmatched += 1;
|
||||||
let statement = &statements[index];
|
|
||||||
println!("{} line {}: {}", statement.path, statement.line, count);
|
|
||||||
}
|
|
||||||
if error_count > 0 {
|
|
||||||
eprintln!("{error_count} lines failed to parse as valid log json");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut counts: Vec<(_, _)> = counts.into_iter().collect();
|
||||||
|
counts.sort_by_key(|(_, count)| *count);
|
||||||
|
counts.reverse();
|
||||||
|
for (index, count) in counts {
|
||||||
|
let statement = &statements[index];
|
||||||
|
println!(
|
||||||
|
"{}: {} line {}: {}",
|
||||||
|
statement.message(),
|
||||||
|
statement.path,
|
||||||
|
statement.line,
|
||||||
|
count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if unmatched > 0 {
|
||||||
|
eprintln!("{unmatched} lines couldn't be matched");
|
||||||
|
}
|
||||||
|
if error_count > 0 {
|
||||||
|
eprintln!("{error_count} lines failed to parse as valid log json");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ pub struct LogMatch {
|
||||||
level: LogLevel,
|
level: LogLevel,
|
||||||
pattern: Regex,
|
pattern: Regex,
|
||||||
pattern_length: usize,
|
pattern_length: usize,
|
||||||
|
has_meaningful_message: bool,
|
||||||
|
exception: Option<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogMatch {
|
impl LogMatch {
|
||||||
|
|
@ -13,6 +15,8 @@ impl LogMatch {
|
||||||
level: statement.level,
|
level: statement.level,
|
||||||
pattern: Regex::new(statement.regex).unwrap(),
|
pattern: Regex::new(statement.regex).unwrap(),
|
||||||
pattern_length: statement.regex.len(),
|
pattern_length: statement.regex.len(),
|
||||||
|
has_meaningful_message: statement.has_meaningful_message,
|
||||||
|
exception: statement.exception,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -33,14 +37,16 @@ impl Matcher {
|
||||||
let mut best_length = 0;
|
let mut best_length = 0;
|
||||||
|
|
||||||
for (i, log_match) in self.matches.iter().enumerate() {
|
for (i, log_match) in self.matches.iter().enumerate() {
|
||||||
if (log_match.level == level
|
if log_match.has_meaningful_message {
|
||||||
|| log_match.level == LogLevel::Exception
|
if (log_match.level == level
|
||||||
|| level == LogLevel::Unknown)
|
|| log_match.level == LogLevel::Exception
|
||||||
&& log_match.pattern.is_match(message)
|
|| level == LogLevel::Unknown)
|
||||||
&& log_match.pattern_length > best_length
|
&& log_match.pattern.is_match(message)
|
||||||
{
|
&& log_match.pattern_length > best_length
|
||||||
best_match = Some(i);
|
{
|
||||||
best_length = log_match.pattern_length;
|
best_match = Some(i);
|
||||||
|
best_length = log_match.pattern_length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue