mirror of
https://codeberg.org/icewind/logsmash.git
synced 2026-06-03 10:04:12 +02:00
initial log extraction logic
This commit is contained in:
commit
572582517c
18 changed files with 2827 additions and 0 deletions
501
logging-extractor/Cargo.lock
generated
Normal file
501
logging-extractor/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "insta"
|
||||
version = "1.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
|
||||
dependencies = [
|
||||
"console",
|
||||
"lazy_static",
|
||||
"linked-hash-map",
|
||||
"serde",
|
||||
"similar",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "logging-extractor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"clap",
|
||||
"insta",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"test-case",
|
||||
"thiserror",
|
||||
"tree-sitter",
|
||||
"tree-sitter-php",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.204"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.120"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
|
||||
dependencies = [
|
||||
"test-case-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-core"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test-case-macros"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"test-case-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter"
|
||||
version = "0.22.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df7cc499ceadd4dcdf7ec6d4cbc34ece92c3fa07821e287aedecd4416c516dca"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tree-sitter-php"
|
||||
version = "0.22.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91010beb390d81a5d720c2d2d87b113892ac38ce3ebc99270183973a066f72e4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"tree-sitter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
26
logging-extractor/Cargo.toml
Normal file
26
logging-extractor/Cargo.toml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
[package]
|
||||
name = "logging-extractor"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.66.0"
|
||||
|
||||
[lib]
|
||||
|
||||
[[bin]]
|
||||
name = "logging-extractor"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.63"
|
||||
clap = { version = "4.5.9", features = ["derive"] }
|
||||
serde = { version = "1.0.204", features = ["derive"] }
|
||||
serde_json = "1.0.120"
|
||||
walkdir = "2.5.0"
|
||||
tree-sitter = "0.22.6"
|
||||
tree-sitter-php = "0.22.7"
|
||||
|
||||
[build-dependencies]
|
||||
cc = "1.1.6"
|
||||
|
||||
[dev-dependencies]
|
||||
test-case = "3.3.1"
|
||||
insta = { version = "1.39.0", features = ["json"] }
|
||||
12
logging-extractor/src/error.rs
Normal file
12
logging-extractor/src/error.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("Failed to determine absolute root path ({}: {err:#}", path.display())]
|
||||
RealPath { path: PathBuf, err: std::io::Error },
|
||||
#[error("Failed to open source file ({}: {err:#}", path.display())]
|
||||
Open { path: PathBuf, err: std::io::Error },
|
||||
#[error("Failed to read source file ({}: {err:#}", path.display())]
|
||||
Read { path: PathBuf, err: std::io::Error },
|
||||
}
|
||||
141
logging-extractor/src/extractor.rs
Normal file
141
logging-extractor/src/extractor.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
use crate::{LogLevel, LoggingStatement};
|
||||
use tree_sitter::{Language, Node, Parser, Query, QueryCursor};
|
||||
|
||||
pub struct LogExtractor {
|
||||
language: Language,
|
||||
method_query: Query,
|
||||
string_query: Query,
|
||||
}
|
||||
|
||||
impl LogExtractor {
|
||||
pub fn new() -> Self {
|
||||
let language = tree_sitter_php::language_php();
|
||||
let method_query = Query::new(
|
||||
&language,
|
||||
r#"(
|
||||
member_call_expression
|
||||
name: (name)@name
|
||||
arguments: (arguments ((argument)+ @args))
|
||||
)"#,
|
||||
)
|
||||
.expect("invalid query");
|
||||
let string_query =
|
||||
Query::new(&language, r#"(string_content)@string"#).expect("invalid query");
|
||||
LogExtractor {
|
||||
language,
|
||||
method_query,
|
||||
string_query,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract<'a>(
|
||||
&self,
|
||||
path: &'a str,
|
||||
code: &'a str,
|
||||
) -> impl Iterator<Item = LoggingStatement<'a>> + 'a {
|
||||
let mut parser = Parser::new();
|
||||
|
||||
parser
|
||||
.set_language(&self.language)
|
||||
.expect("Error loading PHP grammar");
|
||||
parser.set_timeout_micros(10 * 1000 * 1000);
|
||||
|
||||
let tree = parser.parse(code, None).expect("parse timeout or canceled");
|
||||
|
||||
let mut log_call_cursor = QueryCursor::new();
|
||||
let log_calls = self.get_log_calls(&mut log_call_cursor, code, tree.root_node());
|
||||
log_calls
|
||||
.map(|call| {
|
||||
let mut string_cursor = QueryCursor::new();
|
||||
let message_parts = string_cursor
|
||||
.matches(&self.string_query, call.arguments, code.as_bytes())
|
||||
.map(|result| {
|
||||
result.captures[0]
|
||||
.node
|
||||
.utf8_text(code.as_bytes())
|
||||
.unwrap_or("malformed utf8")
|
||||
})
|
||||
.collect();
|
||||
|
||||
LoggingStatement {
|
||||
level: call.level,
|
||||
line: call.line + 1,
|
||||
path,
|
||||
message_parts,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
}
|
||||
|
||||
fn get_log_calls<'a>(
|
||||
&'a self,
|
||||
cursor: &'a mut QueryCursor,
|
||||
code: &'a str,
|
||||
node: Node<'a>,
|
||||
) -> impl Iterator<Item = LogCall> + 'a {
|
||||
let method_calls = cursor.matches(&self.method_query, node, code.as_bytes());
|
||||
|
||||
method_calls.filter_map(|method_call| {
|
||||
let name = method_call.captures[0]
|
||||
.node
|
||||
.utf8_text(code.as_bytes())
|
||||
.unwrap_or("malformed utf8");
|
||||
let level = LogLevel::parse(name)?;
|
||||
let line = method_call.captures[0].node.start_position().row;
|
||||
let arguments = method_call.captures[1].node;
|
||||
Some(LogCall {
|
||||
level,
|
||||
line,
|
||||
arguments,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LogExtractor {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
struct LogCall<'tree> {
|
||||
level: LogLevel,
|
||||
line: usize,
|
||||
arguments: Node<'tree>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_logging() {
|
||||
let code = r#"<?php
|
||||
function test() {
|
||||
$this->logger->warning("failed to find trash item for $rootTrashedItemName deleted at $rootTrashedItemDate in folder $groupFolderId", ['app' => 'groupfolders']);
|
||||
$logger->info("foobar");
|
||||
}
|
||||
?>
|
||||
"#;
|
||||
let extractor = LogExtractor::new();
|
||||
let logs = extractor.extract("foo.php", code).collect::<Vec<_>>();
|
||||
assert_eq!(
|
||||
logs[0],
|
||||
LoggingStatement {
|
||||
path: "foo.php",
|
||||
line: 3,
|
||||
level: LogLevel::Warn,
|
||||
message_parts: vec![
|
||||
"failed to find trash item for ",
|
||||
" deleted at ",
|
||||
" in folder "
|
||||
]
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
logs[1],
|
||||
LoggingStatement {
|
||||
path: "foo.php",
|
||||
line: 4,
|
||||
level: LogLevel::Info,
|
||||
message_parts: vec!["foobar"]
|
||||
}
|
||||
);
|
||||
}
|
||||
72
logging-extractor/src/level.rs
Normal file
72
logging-extractor/src/level.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub enum LogLevel {
|
||||
Debug,
|
||||
Info,
|
||||
Notice,
|
||||
Warn,
|
||||
Error,
|
||||
Alert,
|
||||
Critical,
|
||||
Emergency,
|
||||
#[default]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl LogLevel {
|
||||
pub fn parse(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
"debug" => Some(LogLevel::Debug),
|
||||
"info" => Some(LogLevel::Info),
|
||||
"notice" => Some(LogLevel::Notice),
|
||||
"warn" | "warning" => Some(LogLevel::Warn),
|
||||
"error" => Some(LogLevel::Error),
|
||||
"alert" => Some(LogLevel::Alert),
|
||||
"critical" => Some(LogLevel::Critical),
|
||||
"emergency" => Some(LogLevel::Emergency),
|
||||
"log" => Some(LogLevel::Unknown),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
LogLevel::Debug => "debug",
|
||||
LogLevel::Info => "info",
|
||||
LogLevel::Notice => "notice",
|
||||
LogLevel::Warn => "warn",
|
||||
LogLevel::Error => "error",
|
||||
LogLevel::Alert => "alert",
|
||||
LogLevel::Critical => "critical",
|
||||
LogLevel::Emergency => "emergency",
|
||||
LogLevel::Unknown => "log",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for LogLevel {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.as_str().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for LogLevel {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for LogLevel {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>
|
||||
{
|
||||
let s = <&str>::deserialize(deserializer)?;
|
||||
Ok(LogLevel::parse(s).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
62
logging-extractor/src/lib.rs
Normal file
62
logging-extractor/src/lib.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use crate::error::Error;
|
||||
use crate::extractor::LogExtractor;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub mod error;
|
||||
pub mod extractor;
|
||||
mod level;
|
||||
|
||||
pub use level::LogLevel;
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct LoggingStatement<'a> {
|
||||
level: LogLevel,
|
||||
path: &'a str,
|
||||
line: usize,
|
||||
message_parts: Vec<&'a str>,
|
||||
}
|
||||
|
||||
pub fn extract_dir<W: Write>(root: &str, mut output: W) -> Result<(), Error> {
|
||||
let mut code_buff = String::with_capacity(32 * 1024 * 1024);
|
||||
|
||||
writeln!(&mut output, "[").ok();
|
||||
|
||||
let mut first_line = true;
|
||||
|
||||
let extractor = LogExtractor::new();
|
||||
|
||||
for file in WalkDir::new(root).into_iter().flatten() {
|
||||
let path = file.path();
|
||||
if let Some(path) = path.to_str() {
|
||||
if path.ends_with(".php") {
|
||||
code_buff.clear();
|
||||
|
||||
let rel_path = &path[root.len()..];
|
||||
|
||||
let mut fh = File::open(path).map_err(|err| Error::Open {
|
||||
path: path.into(),
|
||||
err,
|
||||
})?;
|
||||
fh.read_to_string(&mut code_buff)
|
||||
.map_err(|err| Error::Read {
|
||||
path: path.into(),
|
||||
err,
|
||||
})?;
|
||||
for log_item in extractor.extract(rel_path, &code_buff) {
|
||||
if !first_line {
|
||||
writeln!(&mut output, ",").ok();
|
||||
}
|
||||
first_line = false;
|
||||
let _ = serde_json::to_writer(&mut output, &log_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeln!(&mut output, "\n]").ok();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
24
logging-extractor/src/main.rs
Normal file
24
logging-extractor/src/main.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use clap::Parser;
|
||||
use logging_extractor::error::Error;
|
||||
use logging_extractor::extract_dir;
|
||||
use std::fs::canonicalize;
|
||||
use std::io::stdout;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
struct Args {
|
||||
root: PathBuf,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
let args = Args::parse();
|
||||
let root = canonicalize(&args.root).map_err(|err| Error::RealPath {
|
||||
path: args.root,
|
||||
err,
|
||||
})?;
|
||||
let root = root.to_str().expect("non utf8 root path");
|
||||
|
||||
let stdout = stdout();
|
||||
|
||||
extract_dir(root, stdout)
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
12
logging-extractor/tests/snapshot.rs
Normal file
12
logging-extractor/tests/snapshot.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
use logging_extractor::{extract_dir, LoggingStatement};
|
||||
use test_case::test_case;
|
||||
|
||||
#[test_case("DefaultShareProvider")]
|
||||
fn snapshot_test(name: &str) {
|
||||
let root = format!("test-data/{name}");
|
||||
let mut output = Vec::<u8>::with_capacity(1024 * 1024);
|
||||
extract_dir(&root, &mut output).unwrap();
|
||||
let output: Vec<LoggingStatement> = serde_json::from_slice(&output).unwrap();
|
||||
|
||||
insta::assert_json_snapshot!(output)
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
source: tests/snapshot.rs
|
||||
expression: output
|
||||
---
|
||||
[
|
||||
{
|
||||
"level": "error",
|
||||
"path": "/DefaultShareProvider.php",
|
||||
"line": 1171,
|
||||
"message_parts": []
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"path": "/DefaultShareProvider.php",
|
||||
"line": 1392,
|
||||
"message_parts": [
|
||||
"Share notification not sent to ",
|
||||
" because user could not be found."
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"path": "/DefaultShareProvider.php",
|
||||
"line": 1401,
|
||||
"message_parts": [
|
||||
"Share notification not sent to ",
|
||||
" because email address is not set."
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "debug",
|
||||
"path": "/DefaultShareProvider.php",
|
||||
"line": 1416,
|
||||
"message_parts": [
|
||||
"Sent share notification to ",
|
||||
" for share with ID ",
|
||||
"."
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "error",
|
||||
"path": "/DefaultShareProvider.php",
|
||||
"line": 1420,
|
||||
"message_parts": [
|
||||
"Share notification mail could not be sent."
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "error",
|
||||
"path": "/DefaultShareProvider.php",
|
||||
"line": 1507,
|
||||
"message_parts": [
|
||||
"Share notification mail could not be sent to: ",
|
||||
", "
|
||||
]
|
||||
}
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue