diff --git a/.gitignore b/.gitignore index 65f4835c0e..877b107204 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,8 @@ debug/ *.pdb # JetBrains IDE config directory -.idea/ \ No newline at end of file +.idea/ + +# Logs +**/__unittest_logs +logs/ diff --git a/Cargo.lock b/Cargo.lock index 8de5d402e7..5610768767 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,21 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + [[package]] name = "array-init-cursor" version = "0.2.0" @@ -158,6 +173,15 @@ dependencies = [ "syn", ] +[[package]] +name = "atomic-shim" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cd4b51d303cf3501c301e8125df442128d3c6d7c69f71b27833d253de47e77" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "atty" version = "0.2.14" @@ -414,7 +438,7 @@ dependencies = [ "num-integer", "num-traits", "serde", - "time", + "time 0.1.43", "winapi", ] @@ -462,6 +486,7 @@ name = "cmd" version = "0.1.0" dependencies = [ "clap", + "common-telemetry", "datanode", "tokio", ] @@ -510,6 +535,63 @@ dependencies = [ "tokio", ] +[[package]] +name = "common-telemetry" +version = "0.1.0" +dependencies = [ + "backtrace", + "console-subscriber", + "metrics", + "metrics-exporter-prometheus", + "once_cell", + "opentelemetry", + "opentelemetry-jaeger", + "parking_lot 0.12.0", + "tracing", + "tracing-appender", + "tracing-bunyan-formatter", + "tracing-futures", + "tracing-log", + "tracing-opentelemetry", + "tracing-subscriber", +] + +[[package]] +name = "console-api" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24cb05777feccbb2642d4f2df44d0505601a2cd88ca517d8c913f263a5a8dc8b" +dependencies = [ + "prost", + "prost-types", + "tonic", + "tracing-core", +] + +[[package]] +name = "console-subscriber" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f21a16ee925aa9d2bad2e296beffd6c5b1bfaad50af509d305b8e7f23af20fb" +dependencies = [ + "console-api", + "crossbeam-channel", + "crossbeam-utils", + "futures", + "hdrhistogram", + "humantime", + "prost-types", + "serde", + "serde_json", + "thread_local", + "tokio", + "tokio-stream", + "tonic", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -560,6 +642,20 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + [[package]] name = "crossbeam-utils" version = "0.8.8" @@ -627,7 +723,7 @@ dependencies = [ "log", "num_cpus", "ordered-float 2.10.0", - "parking_lot", + "parking_lot 0.12.0", "parquet2", "paste", "pin-project-lite", @@ -694,7 +790,9 @@ dependencies = [ "axum-test-helper", "common-error", "common-recordbatch", + "common-telemetry", "hyper", + "metrics", "query", "serde", "serde_json", @@ -765,6 +863,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fixedbitset" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e" + [[package]] name = "flate2" version = "1.0.23" @@ -907,6 +1011,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" version = "0.2.6" @@ -954,6 +1068,9 @@ name = "hashbrown" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] [[package]] name = "hashbrown" @@ -1042,6 +1159,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.18" @@ -1066,6 +1189,18 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1296,6 +1431,24 @@ dependencies = [ "libc", ] +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "matches" version = "0.1.9" @@ -1323,6 +1476,67 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metrics" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e52eb6380b6d2a10eb3434aec0885374490f5b82c8aaf5cd487a183c98be834" +dependencies = [ + "ahash", + "metrics-macros", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b93b470b04c005178058e18ac8bb2eb3fda562cf87af5ea05ba8d44190d458c" +dependencies = [ + "indexmap", + "metrics", + "metrics-util", + "parking_lot 0.11.2", + "quanta", + "thiserror", +] + +[[package]] +name = "metrics-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e30813093f757be5cf21e50389a24dc7dbb22c49f23b7e8f51d69b508a5ffa" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "metrics-util" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a9e83b833e1d2e07010a386b197c13aa199bbd0fca5cf69bfa147972db890a" +dependencies = [ + "atomic-shim", + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.11.2", + "metrics", + "num_cpus", + "parking_lot 0.11.2", + "quanta", + "sketches-ddsketch", +] + [[package]] name = "mime" version = "0.3.16" @@ -1443,6 +1657,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "object" version = "0.28.3" @@ -1507,6 +1730,51 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand", + "thiserror", + "tokio", + "tokio-stream", +] + +[[package]] +name = "opentelemetry-jaeger" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c0b12cd9e3f9b35b52f6e0dac66866c519b26f424f4bbf96e3fe8bfbdc5229" +dependencies = [ + "async-trait", + "lazy_static", + "opentelemetry", + "opentelemetry-semantic-conventions", + "thiserror", + "thrift", + "tokio", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985cc35d832d412224b2cffe2f9194b1b89b6aa5d0bef76d080dce09d90e62bd" +dependencies = [ + "opentelemetry", +] + [[package]] name = "ordered-float" version = "1.1.1" @@ -1531,6 +1799,17 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + [[package]] name = "parking_lot" version = "0.12.0" @@ -1538,7 +1817,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", ] [[package]] @@ -1547,10 +1840,13 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ + "backtrace", "cfg-if", "libc", + "petgraph", "redox_syscall", "smallvec", + "thread-id", "windows-sys", ] @@ -1597,6 +1893,16 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "petgraph" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a13a2fa9d0b63e5f22328828741e523766fff0ee9e779316902290dff3f824f" +dependencies = [ + "fixedbitset", + "indexmap", +] + [[package]] name = "pin-project" version = "1.0.10" @@ -1683,6 +1989,55 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "prost" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc03e116981ff7d8da8e5c220e374587b98d294af7ba7dd7fda761158f00086f" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b670f45da57fb8542ebdbb6105a925fe571b67f9e7ed9f47a06a84e72b4e7cc" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prost-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d0a014229361011dc8e69c8a1ec6c2e8d0f2af7c91e3ea3f5b2170298461e68" +dependencies = [ + "bytes", + "prost", +] + +[[package]] +name = "quanta" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20afe714292d5e879d8b12740aa223c6a88f118af41870e8b6196e39a02238a8" +dependencies = [ + "crossbeam-utils", + "libc", + "mach", + "once_cell", + "raw-cpuid", + "wasi 0.10.2+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + [[package]] name = "query" version = "0.1.0" @@ -1691,10 +2046,12 @@ dependencies = [ "async-trait", "common-error", "common-recordbatch", + "common-telemetry", "datafusion", "datatypes", "futures", "futures-util", + "metrics", "snafu", "sql", "table", @@ -1741,6 +2098,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "raw-cpuid" +version = "10.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738bc47119e3eeccc7e94c4a506901aea5e7b4944ecd0829cbebf4af04ceda12" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_syscall" version = "0.2.13" @@ -1766,6 +2132,9 @@ name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] [[package]] name = "regex-syntax" @@ -1932,6 +2301,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1947,6 +2325,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "sketches-ddsketch" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a77a8fd93886010f05e7ea0720e569d6d16c65329dbe3ec033bbbccccb017b" + [[package]] name = "slab" version = "0.4.6" @@ -2138,6 +2522,68 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread-id" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +dependencies = [ + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "thrift" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" +dependencies = [ + "byteorder", + "integer-encoding", + "log", + "ordered-float 1.1.1", + "threadpool", +] + [[package]] name = "time" version = "0.1.43" @@ -2148,6 +2594,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa 1.0.1", + "libc", + "num_threads", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -2175,14 +2632,25 @@ dependencies = [ "mio", "num_cpus", "once_cell", - "parking_lot", + "parking_lot 0.12.0", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", + "tracing", "winapi", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "1.7.0" @@ -2243,6 +2711,38 @@ dependencies = [ "tracing", ] +[[package]] +name = "tonic" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9d60db39854b30b835107500cf0aca0b0d14d6e1c3de124217c23a29c2ddb" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "prost-derive", + "tokio", + "tokio-stream", + "tokio-util 0.7.1", + "tower", + "tower-layer", + "tower-service", + "tracing", + "tracing-futures", +] + [[package]] name = "tower" version = "0.4.12" @@ -2319,6 +2819,17 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" +dependencies = [ + "crossbeam-channel", + "time 0.3.9", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.21" @@ -2330,6 +2841,23 @@ dependencies = [ "syn", ] +[[package]] +name = "tracing-bunyan-formatter" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd99ff040622c69c0fc4bd3ea5fe16630ce46400a79bd41339391b2d416ea24c" +dependencies = [ + "gethostname", + "log", + "serde", + "serde_json", + "time 0.3.9", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + [[package]] name = "tracing-core" version = "0.1.26" @@ -2337,6 +2865,61 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" dependencies = [ "lazy_static", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "futures", + "futures-task", + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-opentelemetry" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f9378e96a9361190ae297e7f3a8ff644aacd2897f244b1ff81f381669196fa6" +dependencies = [ + "opentelemetry", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" +dependencies = [ + "ansi_term", + "lazy_static", + "matchers", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -2414,6 +2997,12 @@ dependencies = [ "getrandom", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 89d06f082b..0a8b32ab58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "src/common/base", "src/common/error", + "src/common/telemetry", "src/common/query", "src/common/recordbatch", "src/cmd", diff --git a/src/cmd/Cargo.toml b/src/cmd/Cargo.toml index 506feb02ee..e086428909 100644 --- a/src/cmd/Cargo.toml +++ b/src/cmd/Cargo.toml @@ -9,5 +9,6 @@ path = "src/bin/greptime.rs" [dependencies] clap = { version = "3.1", features = ["derive"] } +common-telemetry = { path = "../common/telemetry" , features = ["deadlock_detection"]} datanode = { path = "../datanode" } tokio = { version = "1.18.0", features = ["full"] } diff --git a/src/cmd/src/bin/greptime.rs b/src/cmd/src/bin/greptime.rs index 4a9a0b6829..c711091cf9 100644 --- a/src/cmd/src/bin/greptime.rs +++ b/src/cmd/src/bin/greptime.rs @@ -1,20 +1,33 @@ use clap::Parser; use cmd::opts::{GrepTimeOpts, NodeType}; +use common_telemetry::{self, logging::error}; use datanode::DataNode; async fn datanode_main(_opts: &GrepTimeOpts) { - let data_node = DataNode::new().unwrap(); + match DataNode::new() { + Ok(data_node) => { + if let Err(e) = data_node.start().await { + error!("Fail to start data node, error: {:?}", e); + } + } - if let Err(e) = data_node.start().await { - println!("Fail to start data node, error: {:?}", e); + Err(e) => error!("Fail to new data node, error: {:?}", e), } } #[tokio::main] async fn main() { let opts = GrepTimeOpts::parse(); + let node_type = opts.node_type; + // TODO(dennis): 1. adds ip/port to app + // 2. config log dir + let app = format!("{node_type:?}-node").to_lowercase(); - match opts.node_type { + common_telemetry::set_panic_hook(); + common_telemetry::init_default_metrics_recorder(); + let _guard = common_telemetry::init_global_logging(&app, "logs", "info", false); + + match node_type { NodeType::Data => datanode_main(&opts).await, } } diff --git a/src/common/telemetry/Cargo.toml b/src/common/telemetry/Cargo.toml new file mode 100644 index 0000000000..85748c5876 --- /dev/null +++ b/src/common/telemetry/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "common-telemetry" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +console = ["console-subscriber"] +deadlock_detection=["parking_lot"] + +[dependencies] +backtrace = "0.3" +console-subscriber = { version = "0.1", optional = true } +metrics = "0.18" +metrics-exporter-prometheus = { version = "0.9", default-features = false } +once_cell = "1.10" +opentelemetry = { version = "0.17", default-features = false, features = ["trace", "rt-tokio"] } +opentelemetry-jaeger = { version = "0.16", features = ["rt-tokio"] } +parking_lot = { version = "0.12", features = ["deadlock_detection"], optional = true } +tracing = "0.1" +tracing-appender = "0.2" +tracing-bunyan-formatter = "0.3" +tracing-futures = { version = "0.2", features = ["futures-03"] } +tracing-log = "0.1" +tracing-opentelemetry = "0.17" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/src/common/telemetry/src/lib.rs b/src/common/telemetry/src/lib.rs new file mode 100644 index 0000000000..c04fd701c4 --- /dev/null +++ b/src/common/telemetry/src/lib.rs @@ -0,0 +1,12 @@ +pub mod logging; +pub mod metric; +mod panic_hook; + +pub use logging::init_default_ut_logging; +pub use logging::init_global_logging; +pub use metric::init_default_metrics_recorder; +pub use panic_hook::set_panic_hook; +pub use tracing; +pub use tracing_appender; +pub use tracing_futures; +pub use tracing_subscriber; diff --git a/src/common/telemetry/src/logging.rs b/src/common/telemetry/src/logging.rs new file mode 100644 index 0000000000..d46c00a45a --- /dev/null +++ b/src/common/telemetry/src/logging.rs @@ -0,0 +1,107 @@ +//! logging stuffs, inspired by databend +use std::env; +use std::sync::Arc; +use std::sync::Mutex; +use std::sync::Once; + +use once_cell::sync::Lazy; +use opentelemetry::global; +use opentelemetry::sdk::propagation::TraceContextPropagator; +pub use tracing::{debug, error, info, span, warn, Level}; +use tracing_appender::non_blocking::WorkerGuard; +use tracing_appender::rolling::RollingFileAppender; +use tracing_appender::rolling::Rotation; +use tracing_bunyan_formatter::BunyanFormattingLayer; +use tracing_bunyan_formatter::JsonStorageLayer; +use tracing_log::LogTracer; +use tracing_subscriber::filter; +use tracing_subscriber::fmt::Layer; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::EnvFilter; +use tracing_subscriber::Registry; + +/// Init tracing for unittest. +/// Write logs to file `unittest`. +pub fn init_default_ut_logging() { + static START: Once = Once::new(); + + START.call_once(|| { + let mut g = GLOBAL_UT_LOG_GUARD.as_ref().lock().unwrap(); + *g = Some(init_global_logging( + "unittest", + "__unittest_logs", + "DEBUG", + false, + )); + }); +} + +static GLOBAL_UT_LOG_GUARD: Lazy>>>> = + Lazy::new(|| Arc::new(Mutex::new(None))); + +pub fn init_global_logging( + app_name: &str, + dir: &str, + level: &str, + enable_jaeger_tracing: bool, +) -> Vec { + let mut guards = vec![]; + + // Enable log compatible layer to convert log record to tracing span. + LogTracer::init().expect("log tracer must be valid"); + + // Stdout layer. + let (stdout_writer, stdout_guard) = tracing_appender::non_blocking(std::io::stdout()); + let stdout_logging_layer = Layer::new().with_writer(stdout_writer); + guards.push(stdout_guard); + + // JSON log layer. + let rolling_appender = RollingFileAppender::new(Rotation::HOURLY, dir, app_name); + let (rolling_writer, rolling_writer_guard) = tracing_appender::non_blocking(rolling_appender); + let file_logging_layer = BunyanFormattingLayer::new(app_name.to_string(), rolling_writer); + guards.push(rolling_writer_guard); + + // Use env RUST_LOG to initialize log if present. + // Otherwise use the specified level. + let directives = env::var(EnvFilter::DEFAULT_ENV).unwrap_or_else(|_x| level.to_string()); + let filter = filter::Targets::new() + // Only enable WARN and ERROR for 3rd-party crates + // TODO(dennis): configure them? + .with_target("hyper", Level::WARN) + .with_target("tower", Level::WARN) + .with_target("datafusion", Level::WARN) + .with_target("reqwest", Level::WARN) + .with_default( + directives + .parse::() + .expect("error parsing level string"), + ); + + let subscriber = Registry::default() + .with(filter) + .with(JsonStorageLayer) + .with(stdout_logging_layer) + .with(file_logging_layer); + + // Must enable 'tokio_unstable' cfg, https://github.com/tokio-rs/console + #[cfg(feature = "console")] + let subscriber = subscriber.with(console_subscriber::spawn()); + + if enable_jaeger_tracing { + // Jaeger layer. + global::set_text_map_propagator(TraceContextPropagator::new()); + let tracer = opentelemetry_jaeger::new_pipeline() + .with_service_name(app_name) + .install_batch(opentelemetry::runtime::Tokio) + .expect("install"); + let jaeger_layer = Some(tracing_opentelemetry::layer().with_tracer(tracer)); + let subscriber = subscriber.with(jaeger_layer); + tracing::subscriber::set_global_default(subscriber) + .expect("error setting global tracing subscriber"); + } else { + tracing::subscriber::set_global_default(subscriber) + .expect("error setting global tracing subscriber"); + } + + guards +} diff --git a/src/common/telemetry/src/metric.rs b/src/common/telemetry/src/metric.rs new file mode 100644 index 0000000000..22694e5f6c --- /dev/null +++ b/src/common/telemetry/src/metric.rs @@ -0,0 +1,91 @@ +// metric stuffs, inspired by databend + +use std::sync::{Arc, Once, RwLock}; +use std::time::{Duration, Instant}; + +use metrics::histogram; +use metrics_exporter_prometheus::PrometheusBuilder; +pub use metrics_exporter_prometheus::PrometheusHandle; +use once_cell::sync::Lazy; + +use crate::logging; + +static PROMETHEUS_HANDLE: Lazy>>> = + Lazy::new(|| Arc::new(RwLock::new(None))); + +pub fn init_default_metrics_recorder() { + static START: Once = Once::new(); + START.call_once(init_prometheus_recorder) +} + +/// Init prometheus recorder. +fn init_prometheus_recorder() { + let recorder = PrometheusBuilder::new().build_recorder(); + let mut h = PROMETHEUS_HANDLE.as_ref().write().unwrap(); + *h = Some(recorder.handle()); + metrics::clear_recorder(); + match metrics::set_boxed_recorder(Box::new(recorder)) { + Ok(_) => (), + Err(err) => logging::warn!("Install prometheus recorder failed, cause: {}", err), + }; +} + +pub fn try_handle() -> Option { + PROMETHEUS_HANDLE.as_ref().read().unwrap().clone() +} + +#[must_use = "Timer should be kept in a variable otherwise it cannot observe duration"] +#[derive(Debug)] +pub struct Timer { + start: Instant, + name: &'static str, +} + +impl Timer { + pub fn new(name: &'static str) -> Self { + Self { + start: Instant::now(), + name, + } + } + + pub fn elapsed(&self) -> Duration { + self.start.elapsed() + } +} + +impl Drop for Timer { + fn drop(&mut self) { + histogram!(self.name, self.start.elapsed()); + } +} + +#[macro_export] +macro_rules! timer { + ($name: expr) => { + $crate::metric::Timer::new($name) + }; +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_elapsed_timer() { + init_default_metrics_recorder(); + { + let t = Timer::new("test_elapsed_timer_a"); + drop(t); + } + let handle = try_handle().unwrap(); + let text = handle.render(); + assert!(text.contains("test_elapsed_timer_a")); + assert!(!text.contains("test_elapsed_timer_b")); + + let _ = timer!("test_elapsed_timer_b"); + let text = handle.render(); + assert!(text.contains("test_elapsed_timer_a")); + assert!(text.contains("test_elapsed_timer_b")); + } +} diff --git a/src/common/telemetry/src/panic_hook.rs b/src/common/telemetry/src/panic_hook.rs new file mode 100644 index 0000000000..0895450b81 --- /dev/null +++ b/src/common/telemetry/src/panic_hook.rs @@ -0,0 +1,49 @@ +use std::panic; +#[cfg(feature = "deadlock_detection")] +use std::time::Duration; + +use backtrace::Backtrace; + +pub fn set_panic_hook() { + // Set a panic hook that records the panic as a `tracing` event at the + // `ERROR` verbosity level. + // + // If we are currently in a span when the panic occurred, the logged event + // will include the current span, allowing the context in which the panic + // occurred to be recorded. + let default_hook = panic::take_hook(); + panic::set_hook(Box::new(move |panic| { + let backtrace = Backtrace::new(); + let backtrace = format!("{:?}", backtrace); + if let Some(location) = panic.location() { + tracing::error!( + message = %panic, + backtrace = %backtrace, + panic.file = location.file(), + panic.line = location.line(), + panic.column = location.column(), + ); + } else { + tracing::error!(message = %panic, backtrace = %backtrace); + } + default_hook(panic); + })); + + #[cfg(feature = "deadlock_detection")] + std::thread::spawn(move || loop { + std::thread::sleep(Duration::from_secs(5)); + let deadlocks = parking_lot::deadlock::check_deadlock(); + if deadlocks.is_empty() { + continue; + } + + tracing::info!("{} deadlocks detected", deadlocks.len()); + for (i, threads) in deadlocks.iter().enumerate() { + tracing::info!("Deadlock #{}", i); + for t in threads { + tracing::info!("Thread Id {:#?}", t.thread_id()); + tracing::info!("{:#?}", t.backtrace()); + } + } + }); +} diff --git a/src/datanode/Cargo.toml b/src/datanode/Cargo.toml index 45b7d22f95..541314eb2f 100644 --- a/src/datanode/Cargo.toml +++ b/src/datanode/Cargo.toml @@ -10,7 +10,9 @@ axum = "0.5" axum-macros = "0.2" common-error = { path = "../common/error" } common-recordbatch = { path = "../common/recordbatch" } +common-telemetry = { path = "../common/telemetry" } hyper = { version = "0.14", features = ["full"] } +metrics = "0.18" query = { path = "../query" } serde = "1.0" serde_json = "1.0" diff --git a/src/datanode/src/lib.rs b/src/datanode/src/lib.rs index dc06b9136c..57de3c7e56 100644 --- a/src/datanode/src/lib.rs +++ b/src/datanode/src/lib.rs @@ -2,6 +2,7 @@ pub mod catalog; pub mod datanode; pub mod error; pub mod instance; +mod metric; pub mod server; pub use crate::datanode::DataNode; diff --git a/src/datanode/src/metric.rs b/src/datanode/src/metric.rs new file mode 100644 index 0000000000..8160988bfd --- /dev/null +++ b/src/datanode/src/metric.rs @@ -0,0 +1,3 @@ +//! datanode metrics + +pub const METRIC_HANDLE_SQL_ELAPSED: &str = "datanode.handle_sql_elapsed"; diff --git a/src/datanode/src/server/http.rs b/src/datanode/src/server/http.rs index 9d302a83fb..b186a1431a 100644 --- a/src/datanode/src/server/http.rs +++ b/src/datanode/src/server/http.rs @@ -11,6 +11,7 @@ use axum::{ BoxError, Extension, Router, }; use common_recordbatch::{util, RecordBatch}; +use common_telemetry::logging::info; use query::Output; use serde::Serialize; use snafu::ResultExt; @@ -31,6 +32,14 @@ pub enum JsonOutput { Rows(Vec), } +/// Http response +#[derive(Serialize, Debug)] +pub enum HttpResponse { + Json(JsonResponse), + Text(String), +} + +/// Json response #[derive(Serialize, Debug)] pub struct JsonResponse { success: bool, @@ -40,9 +49,12 @@ pub struct JsonResponse { output: Option, } -impl IntoResponse for JsonResponse { +impl IntoResponse for HttpResponse { fn into_response(self) -> Response { - Json(self).into_response() + match self { + HttpResponse::Json(json) => Json(json).into_response(), + HttpResponse::Text(text) => text.into_response(), + } } } @@ -91,22 +103,26 @@ impl HttpServer { } pub fn make_app(&self) -> Router { - Router::new().route("/sql", get(handler::sql)).layer( - ServiceBuilder::new() - .layer(HandleErrorLayer::new(handle_error)) - .layer(TraceLayer::new_for_http()) - .layer(Extension(self.instance.clone())) - // TODO configure timeout - .layer(TimeoutLayer::new(Duration::from_secs(30))), - ) + Router::new() + // handlers + .route("/sql", get(handler::sql)) + .route("/metrics", get(handler::metrics)) + // middlewares + .layer( + ServiceBuilder::new() + .layer(HandleErrorLayer::new(handle_error)) + .layer(TraceLayer::new_for_http()) + .layer(Extension(self.instance.clone())) + // TODO configure timeout + .layer(TimeoutLayer::new(Duration::from_secs(30))), + ) } pub async fn start(&self) -> Result<()> { let app = self.make_app(); let addr = SocketAddr::from(([0, 0, 0, 0], 3000)); - // TODO(dennis): log - println!("Datanode HTTP server is listening on {}", addr); + info!("Datanode HTTP server is listening on {}", addr); let server = axum::Server::bind(&addr).serve(app.into_make_service()); let graceful = server.with_graceful_shutdown(shutdown_signal()); diff --git a/src/datanode/src/server/http/handler.rs b/src/datanode/src/server/http/handler.rs index 5980e0a75a..1e205237a8 100644 --- a/src/datanode/src/server/http/handler.rs +++ b/src/datanode/src/server/http/handler.rs @@ -3,20 +3,38 @@ use std::collections::HashMap; use axum::extract::{Extension, Query}; +use common_telemetry::{metric, timer}; use crate::instance::InstanceRef; -use crate::server::http::JsonResponse; +use crate::metric::METRIC_HANDLE_SQL_ELAPSED; +use crate::server::http::{HttpResponse, JsonResponse}; /// Handler to execute sql #[axum_macros::debug_handler] pub async fn sql( Extension(instance): Extension, Query(params): Query>, -) -> JsonResponse { +) -> HttpResponse { + let _timer = timer!(METRIC_HANDLE_SQL_ELAPSED); if let Some(sql) = params.get("sql") { - JsonResponse::from_output(instance.execute_sql(sql).await).await + HttpResponse::Json(JsonResponse::from_output(instance.execute_sql(sql).await).await) } else { - JsonResponse::with_error(Some("sql parameter is required.".to_string())) + HttpResponse::Json(JsonResponse::with_error(Some( + "sql parameter is required.".to_string(), + ))) + } +} + +/// Handler to export metrics +#[axum_macros::debug_handler] +pub async fn metrics( + Extension(_instance): Extension, + Query(_params): Query>, +) -> HttpResponse { + if let Some(handle) = metric::try_handle() { + HttpResponse::Text(handle.render()) + } else { + HttpResponse::Text("Prometheus handle not initialized.".to_string()) } } @@ -24,6 +42,7 @@ pub async fn sql( mod tests { use std::sync::Arc; + use metrics::counter; use query::catalog::memory; use super::*; @@ -50,9 +69,14 @@ mod tests { let extension = create_extension(); let json = sql(extension, Query(HashMap::default())).await; - assert!(!json.success); - assert_eq!(Some("sql parameter is required.".to_string()), json.error); - assert!(json.output.is_none()); + match json { + HttpResponse::Json(json) => { + assert!(!json.success); + assert_eq!(Some("sql parameter is required.".to_string()), json.error); + assert!(json.output.is_none()); + } + _ => unreachable!(), + } } #[tokio::test] @@ -61,15 +85,37 @@ mod tests { let extension = create_extension(); let json = sql(extension, query).await; - assert!(json.success); - assert!(json.error.is_none()); - assert!(json.output.is_some()); - match json.output.unwrap() { - JsonOutput::Rows(rows) => { - assert_eq!(1, rows.len()); + match json { + HttpResponse::Json(json) => { + assert!(json.success); + assert!(json.error.is_none()); + assert!(json.output.is_some()); + + match json.output.unwrap() { + JsonOutput::Rows(rows) => { + assert_eq!(1, rows.len()); + } + _ => unreachable!(), + } } _ => unreachable!(), } } + + #[tokio::test] + async fn test_metrics() { + metric::init_default_metrics_recorder(); + + counter!("test_metrics", 1); + + let query = create_params(); + let extension = create_extension(); + let text = metrics(extension, query).await; + + match text { + HttpResponse::Text(s) => assert!(s.contains("test_metrics counter")), + _ => unreachable!(), + } + } } diff --git a/src/datanode/tests/http_test.rs b/src/datanode/tests/http_test.rs index 662835afd0..fcc4c60975 100644 --- a/src/datanode/tests/http_test.rs +++ b/src/datanode/tests/http_test.rs @@ -17,6 +17,7 @@ fn make_test_app() -> Router { #[tokio::test] async fn test_sql_api() { + common_telemetry::init_default_ut_logging(); let app = make_test_app(); let client = TestClient::new(app); let res = client.get("/sql").send().await; @@ -41,3 +42,24 @@ async fn test_sql_api() { r#"{"success":true,"output":{"Rows":[{"schema":{"fields":[{"name":"number","data_type":"UInt32","is_nullable":false,"metadata":{}}],"metadata":{}},"columns":[{"UInt32":[0,1,2,3,4,5,6,7,8,9]}]}]}}"# ); } + +#[tokio::test] +async fn test_metrics_api() { + common_telemetry::init_default_ut_logging(); + common_telemetry::init_default_metrics_recorder(); + let app = make_test_app(); + let client = TestClient::new(app); + + // Send a sql + let res = client + .get("/sql?sql=select * from numbers limit 10") + .send() + .await; + assert_eq!(res.status(), StatusCode::OK); + + // Call metrics api + let res = client.get("/metrics").send().await; + assert_eq!(res.status(), StatusCode::OK); + let body = res.text().await; + assert!(body.contains("datanode_handle_sql_elapsed")); +} diff --git a/src/query/Cargo.toml b/src/query/Cargo.toml index 9462ce3753..5afc9f38ae 100644 --- a/src/query/Cargo.toml +++ b/src/query/Cargo.toml @@ -12,10 +12,12 @@ features = ["io_csv", "io_json", "io_parquet", "io_parquet_compression", "io_ipc async-trait = "0.1" common-error = { path = "../common/error" } common-recordbatch = {path = "../common/recordbatch" } +common-telemetry = { path = "../common/telemetry" } datafusion = { git = "https://github.com/apache/arrow-datafusion.git" , branch = "arrow2", features = ["simd"]} datatypes = {path = "../datatypes" } futures = "0.3" -futures-util = "0.3.21" +futures-util = "0.3" +metrics = "0.18" snafu = { version = "0.7", features = ["backtraces"] } table = { path = "../table" } tokio = "1.0" diff --git a/src/query/src/datafusion.rs b/src/query/src/datafusion.rs index 700a33534e..d8148c2f02 100644 --- a/src/query/src/datafusion.rs +++ b/src/query/src/datafusion.rs @@ -8,10 +8,12 @@ mod planner; use std::sync::Arc; use common_recordbatch::{EmptyRecordBatchStream, SendableRecordBatchStream}; +use common_telemetry::timer; use snafu::{OptionExt, ResultExt}; use sql::{dialect::GenericDialect, parser::ParserContext}; pub use crate::datafusion::catalog_adapter::DfCatalogListAdapter; +use crate::metric; use crate::query_engine::{QueryContext, QueryEngineState}; use crate::{ catalog::CatalogListRef, @@ -46,6 +48,7 @@ impl QueryEngine for DatafusionQueryEngine { } fn sql_to_plan(&self, sql: &str) -> Result { + let _timer = timer!(metric::METRIC_PARSE_SQL_ELAPSED); let context_provider = DfContextProviderAdapter::new(self.state.catalog_list()); let planner = DfPlanner::new(&context_provider); let mut statement = ParserContext::create_with_dialect(sql, &GenericDialect {}) @@ -73,6 +76,7 @@ impl LogicalOptimizer for DatafusionQueryEngine { _ctx: &mut QueryContext, plan: &LogicalPlan, ) -> Result { + let _timer = timer!(metric::METRIC_OPTIMIZE_LOGICAL_ELAPSED); match plan { LogicalPlan::DfPlan(df_plan) => { let optimized_plan = @@ -96,6 +100,7 @@ impl PhysicalPlanner for DatafusionQueryEngine { _ctx: &mut QueryContext, logical_plan: &LogicalPlan, ) -> Result> { + let _timer = timer!(metric::METRIC_CREATE_PHYSICAL_ELAPSED); match logical_plan { LogicalPlan::DfPlan(df_plan) => { let physical_plan = self @@ -122,6 +127,7 @@ impl PhysicalOptimizer for DatafusionQueryEngine { _ctx: &mut QueryContext, plan: Arc, ) -> Result> { + let _timer = timer!(metric::METRIC_OPTIMIZE_PHYSICAL_ELAPSED); let config = &self.state.df_context().state.lock().config; let optimizers = &config.physical_optimizers; @@ -150,6 +156,7 @@ impl QueryExecutor for DatafusionQueryEngine { ctx: &QueryContext, plan: &Arc, ) -> Result { + let _timer = timer!(metric::METRIC_EXEC_PLAN_ELAPSED); match plan.output_partitioning().partition_count() { 0 => Ok(Box::pin(EmptyRecordBatchStream::new(plan.schema()))), 1 => Ok(plan.execute(&ctx.state().runtime(), 0).await?), diff --git a/src/query/src/lib.rs b/src/query/src/lib.rs index c77401c603..0f10661b4d 100644 --- a/src/query/src/lib.rs +++ b/src/query/src/lib.rs @@ -4,6 +4,7 @@ mod datafusion; pub mod error; pub mod executor; pub mod logical_optimizer; +mod metric; pub mod physical_optimizer; pub mod physical_planner; pub mod plan; diff --git a/src/query/src/metric.rs b/src/query/src/metric.rs new file mode 100644 index 0000000000..1c843f7ee7 --- /dev/null +++ b/src/query/src/metric.rs @@ -0,0 +1,7 @@ +//! query engine metrics + +pub static METRIC_PARSE_SQL_ELAPSED: &str = "query.parse_sql_elapsed"; +pub static METRIC_OPTIMIZE_LOGICAL_ELAPSED: &str = "query.optimize_logicalplan_elapsed"; +pub static METRIC_OPTIMIZE_PHYSICAL_ELAPSED: &str = "query.optimize_physicalplan_elapsed"; +pub static METRIC_CREATE_PHYSICAL_ELAPSED: &str = "query.create_physicalplan_elapsed"; +pub static METRIC_EXEC_PLAN_ELAPSED: &str = "query.execute_plan_elapsed"; diff --git a/src/query/tests/query_engine_test.rs b/src/query/tests/query_engine_test.rs index 5032d4dd5e..3995d3a29d 100644 --- a/src/query/tests/query_engine_test.rs +++ b/src/query/tests/query_engine_test.rs @@ -14,6 +14,7 @@ use table::table::numbers::NumbersTable; #[tokio::test] async fn test_datafusion_query_engine() -> Result<()> { + common_telemetry::init_default_ut_logging(); let catalog_list = memory::new_memory_catalog_list()?; let factory = QueryEngineFactory::new(catalog_list); let engine = factory.query_engine();