Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/env_logger/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/env_logger/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.lock":"170dbbf90750a0bfa1779871d573233559bfddd8e5b25340b50e76b95277da35","Cargo.toml":"255124834d355853645a6a9b42a6a6789b30bcd1eb1b7cebd1c5b5967f6f0aa5","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"b218c2181d8373dabc42f12527f85cdbd7a2d789905c67d3a969adb75096e981","examples/custom_default_format.rs":"321df9186b781ab377a9fc8ce69108c2649d2943fe26eff86cf899d4d3dd69f5","examples/custom_format.rs":"dbdf157c45a071e491cbe1038ad83d50a0154ea0691ee07dc4bd15fc1ca9205f","examples/custom_logger.rs":"1a84203df4d424acba8cba50b5eb6d44bd5e41daa0ed2226494bbfd45ee9f4e9","examples/default.rs":"1e1d9f5b7744861e7f84f95f607d1ae709d93261096387323a4039df31cbf1c1","examples/direct_logger.rs":"5ae565fab0583c06de4cc3554fb4c8dc64cee8e2e1337b9aafff44e1bfb94e43","examples/filters_from_code.rs":"a2e8dbcb949a19de9228654907019e876a0689750d1c86e04fea606585a79938","examples/in_tests.rs":"b31884a7eeb8d316b55a829a7bacc45da248733ae17a263dc1af68394fb309ab","examples/syslog_friendly_format.rs":"4269a86f549253bad54c7e8aae03d5ab09959a5c9d798d3fc6c4745cd5d96cd9","src/filter/mod.rs":"dccde51e29d7f2b2151da9b6447f30215cdd6e7e0fecf3de8f231d919563cb76","src/filter/regex.rs":"bdf875bac25e089e1e462f5dd01a88678067c24118ecd6268561c6a6af39747d","src/filter/string.rs":"fac54d51189fc0b5d2bff334b7a7e465177b431e3428299e345e1f90062d832e","src/fmt/humantime.rs":"515ebf2c201e0fdb79d36a4c542349e70163fd86af8a6448286ee3d826e58a81","src/fmt/mod.rs":"ea13c4dbfdceb82b5dba9b9a998c20b124d86555b180875a8c151355f1a798d7","src/fmt/style.rs":"a173552c819d892fde779520456a9173a755e109cbc73845504ce1c5bf77ad89","src/fmt/writer/atty.rs":"098f4c358177d34b0d5a8202ac308f23b08a694b053557c6213f73ab29f8d96e","src/fmt/writer/buffer/mod.rs":"48572ff8f0bf4a60939fbb5b3a82f3bf82cf7c50170eb15165cd3c19d997c901","src/fmt/writer/buffer/plain.rs":"dd408702340d99b456a21a10c979d1f18d71aaa6a9b0c03dbc77c7ea46b2bdfa","src/fmt/writer/buffer/termcolor.rs":"694201b3bea6f4f788bc5023e5084684b42fd63e58a99c0334d9304469e0b91b","src/fmt/writer/mod.rs":"528bc3a8fba29193c1365af0afa04099f8fb4d01f4d1f1701bc7ad356ee8cf92","src/lib.rs":"6cad01c0d1f140c1b2597eec363c4a4958929a1d9f57c954279121a8abd84e0a","src/logger.rs":"3f1b7723eba17b320ae7e5517f17ffc1f32a943f8cf3c2a2d76497f0fdc3798f","tests/init-twice-retains-filter.rs":"be5cd2132342d89ede1f5c4266173bb3c4d51cc22a1847f133d299a1c5430ccb","tests/log-in-log.rs":"29fecc65c1e0d1c22d79c97e7ca843ad44a91f27934148d7a05c48899a3f39d8","tests/log_tls_dtors.rs":"7320667d774a9b05037f7bf273fb2574dec0705707692a9cd2f46f4cd5bc68dd","tests/regexp_filter.rs":"a84263c995b534b6479a1d0abadf63f4f0264958ff86d9173d6b2139b82c4dc5"},"package":"4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"}
|
||||
254
third-party/vendor/env_logger/Cargo.lock
generated
vendored
Normal file
254
third-party/vendor/env_logger/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
dependencies = [
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7d367024b3f3414d8e01f437f704f41a9f64ab36f9067fa73e526ad4c763c87"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aae5bc6e2eb41c9def29a3e0f1306382807764b9b53112030eff57435667352d"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b1fbb4dfc4eb1d390c02df47760bb19a84bb80b301ecc947ab5406394d8223e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
137
third-party/vendor/env_logger/Cargo.toml
vendored
Normal file
137
third-party/vendor/env_logger/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.60.0"
|
||||
name = "env_logger"
|
||||
version = "0.10.2"
|
||||
include = [
|
||||
"build.rs",
|
||||
"src/**/*",
|
||||
"Cargo.toml",
|
||||
"Cargo.lock",
|
||||
"LICENSE*",
|
||||
"README.md",
|
||||
"benches/**/*",
|
||||
"examples/**/*",
|
||||
"tests/**/*",
|
||||
]
|
||||
description = """
|
||||
A logging implementation for `log` which is configured via an environment
|
||||
variable.
|
||||
"""
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"logging",
|
||||
"log",
|
||||
"logger",
|
||||
]
|
||||
categories = ["development-tools::debugging"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-cli/env_logger"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
min = 1
|
||||
replace = "{{version}}"
|
||||
search = "Unreleased"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "CHANGELOG.md"
|
||||
replace = "...{{tag_name}}"
|
||||
search = '\.\.\.HEAD'
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
file = "CHANGELOG.md"
|
||||
min = 1
|
||||
replace = "{{date}}"
|
||||
search = "ReleaseDate"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "CHANGELOG.md"
|
||||
replace = """
|
||||
<!-- next-header -->
|
||||
## [Unreleased] - ReleaseDate
|
||||
"""
|
||||
search = "<!-- next-header -->"
|
||||
|
||||
[[package.metadata.release.pre-release-replacements]]
|
||||
exactly = 1
|
||||
file = "CHANGELOG.md"
|
||||
replace = """
|
||||
<!-- next-url -->
|
||||
[Unreleased]: https://github.com/rust-cli/env_logger/compare/{{tag_name}}...HEAD"""
|
||||
search = "<!-- next-url -->"
|
||||
|
||||
[[test]]
|
||||
name = "regexp_filter"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "log-in-log"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "log_tls_dtors"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "init-twice-retains-filter"
|
||||
harness = false
|
||||
|
||||
[dependencies.humantime]
|
||||
version = "2.0.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.is-terminal]
|
||||
version = "0.4.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.log]
|
||||
version = "0.4.8"
|
||||
features = ["std"]
|
||||
|
||||
[dependencies.regex]
|
||||
version = "1.0.3"
|
||||
features = [
|
||||
"std",
|
||||
"perf",
|
||||
]
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.termcolor]
|
||||
version = "1.1.1"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
auto-color = [
|
||||
"dep:is-terminal",
|
||||
"color",
|
||||
]
|
||||
color = ["dep:termcolor"]
|
||||
default = [
|
||||
"auto-color",
|
||||
"humantime",
|
||||
"regex",
|
||||
]
|
||||
humantime = ["dep:humantime"]
|
||||
regex = ["dep:regex"]
|
||||
202
third-party/vendor/env_logger/LICENSE-APACHE
vendored
Normal file
202
third-party/vendor/env_logger/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
19
third-party/vendor/env_logger/LICENSE-MIT
vendored
Normal file
19
third-party/vendor/env_logger/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) Individual contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
177
third-party/vendor/env_logger/README.md
vendored
Normal file
177
third-party/vendor/env_logger/README.md
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
# env_logger
|
||||
|
||||
[](https://crates.io/crates/env_logger)
|
||||
[](https://docs.rs/env_logger)
|
||||
|
||||
Implements a logger that can be configured via environment variables.
|
||||
|
||||
## Usage
|
||||
|
||||
### In libraries
|
||||
|
||||
`env_logger` makes sense when used in executables (binary projects). Libraries should use the [`log`](https://docs.rs/log) crate instead.
|
||||
|
||||
### In executables
|
||||
|
||||
It must be added along with `log` to the project dependencies:
|
||||
|
||||
```console
|
||||
$ cargo add log env_logger
|
||||
```
|
||||
|
||||
`env_logger` must be initialized as early as possible in the project. After it's initialized, you can use the `log` macros to do actual logging.
|
||||
|
||||
```rust
|
||||
use log::info;
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
info!("starting up");
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Then when running the executable, specify a value for the **`RUST_LOG`**
|
||||
environment variable that corresponds with the log messages you want to show.
|
||||
|
||||
```bash
|
||||
$ RUST_LOG=info ./main
|
||||
[2018-11-03T06:09:06Z INFO default] starting up
|
||||
```
|
||||
|
||||
The letter case is not significant for the logging level names; e.g., `debug`,
|
||||
`DEBUG`, and `dEbuG` all represent the same logging level. Therefore, the
|
||||
previous example could also have been written this way, specifying the log
|
||||
level as `INFO` rather than as `info`:
|
||||
|
||||
```bash
|
||||
$ RUST_LOG=INFO ./main
|
||||
[2018-11-03T06:09:06Z INFO default] starting up
|
||||
```
|
||||
|
||||
So which form should you use? For consistency, our convention is to use lower
|
||||
case names. Where our docs do use other forms, they do so in the context of
|
||||
specific examples, so you won't be surprised if you see similar usage in the
|
||||
wild.
|
||||
|
||||
The log levels that may be specified correspond to the [`log::Level`][level-enum]
|
||||
enum from the `log` crate. They are:
|
||||
|
||||
* `error`
|
||||
* `warn`
|
||||
* `info`
|
||||
* `debug`
|
||||
* `trace`
|
||||
|
||||
[level-enum]: https://docs.rs/log/latest/log/enum.Level.html "log::Level (docs.rs)"
|
||||
|
||||
There is also a pseudo logging level, `off`, which may be specified to disable
|
||||
all logging for a given module or for the entire application. As with the
|
||||
logging levels, the letter case is not significant.
|
||||
|
||||
`env_logger` can be configured in other ways besides an environment variable. See [the examples](https://github.com/rust-cli/env_logger/tree/main/examples) for more approaches.
|
||||
|
||||
### In tests
|
||||
|
||||
Tests can use the `env_logger` crate to see log messages generated during that test:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
log = "0.4.0"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.10.0"
|
||||
```
|
||||
|
||||
```rust
|
||||
fn add_one(num: i32) -> i32 {
|
||||
info!("add_one called with {}", num);
|
||||
num + 1
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use log::info;
|
||||
|
||||
fn init() {
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_adds_one() {
|
||||
init();
|
||||
|
||||
info!("can log from the test too");
|
||||
assert_eq!(3, add_one(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_handles_negative_numbers() {
|
||||
init();
|
||||
|
||||
info!("logging from another test");
|
||||
assert_eq!(-7, add_one(-8));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Assuming the module under test is called `my_lib`, running the tests with the
|
||||
`RUST_LOG` filtering to info messages from this module looks like:
|
||||
|
||||
```bash
|
||||
$ RUST_LOG=my_lib=info cargo test
|
||||
Running target/debug/my_lib-...
|
||||
|
||||
running 2 tests
|
||||
[INFO my_lib::tests] logging from another test
|
||||
[INFO my_lib] add_one called with -8
|
||||
test tests::it_handles_negative_numbers ... ok
|
||||
[INFO my_lib::tests] can log from the test too
|
||||
[INFO my_lib] add_one called with 2
|
||||
test tests::it_adds_one ... ok
|
||||
|
||||
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
Note that `env_logger::try_init()` needs to be called in each test in which you
|
||||
want to enable logging. Additionally, the default behavior of tests to
|
||||
run in parallel means that logging output may be interleaved with test output.
|
||||
Either run tests in a single thread by specifying `RUST_TEST_THREADS=1` or by
|
||||
running one test by specifying its name as an argument to the test binaries as
|
||||
directed by the `cargo test` help docs:
|
||||
|
||||
```bash
|
||||
$ RUST_LOG=my_lib=info cargo test it_adds_one
|
||||
Running target/debug/my_lib-...
|
||||
|
||||
running 1 test
|
||||
[INFO my_lib::tests] can log from the test too
|
||||
[INFO my_lib] add_one called with 2
|
||||
test tests::it_adds_one ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
## Configuring log target
|
||||
|
||||
By default, `env_logger` logs to stderr. If you want to log to stdout instead,
|
||||
you can use the `Builder` to change the log target:
|
||||
|
||||
```rust
|
||||
use std::env;
|
||||
use env_logger::{Builder, Target};
|
||||
|
||||
let mut builder = Builder::from_default_env();
|
||||
builder.target(Target::Stdout);
|
||||
|
||||
builder.init();
|
||||
```
|
||||
|
||||
## Stability of the default format
|
||||
|
||||
The default format won't optimise for long-term stability, and explicitly makes no guarantees about the stability of its output across major, minor or patch version bumps during `0.x`.
|
||||
|
||||
If you want to capture or interpret the output of `env_logger` programmatically then you should use a custom format.
|
||||
39
third-party/vendor/env_logger/examples/custom_default_format.rs
vendored
Normal file
39
third-party/vendor/env_logger/examples/custom_default_format.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*!
|
||||
Disabling parts of the default format.
|
||||
|
||||
Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
|
||||
|
||||
```no_run,shell
|
||||
$ export MY_LOG_LEVEL='info'
|
||||
```
|
||||
|
||||
Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors
|
||||
or `auto` to enable them:
|
||||
|
||||
```no_run,shell
|
||||
$ export MY_LOG_STYLE=never
|
||||
```
|
||||
|
||||
If you want to control the logging output completely, see the `custom_logger` example.
|
||||
*/
|
||||
|
||||
use log::info;
|
||||
|
||||
use env_logger::{Builder, Env};
|
||||
|
||||
fn init_logger() {
|
||||
let env = Env::default()
|
||||
.filter("MY_LOG_LEVEL")
|
||||
.write_style("MY_LOG_STYLE");
|
||||
|
||||
Builder::from_env(env)
|
||||
.format_level(false)
|
||||
.format_timestamp_nanos()
|
||||
.init();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
init_logger();
|
||||
|
||||
info!("a log from `MyLogger`");
|
||||
}
|
||||
54
third-party/vendor/env_logger/examples/custom_format.rs
vendored
Normal file
54
third-party/vendor/env_logger/examples/custom_format.rs
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*!
|
||||
Changing the default logging format.
|
||||
|
||||
Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
|
||||
|
||||
```no_run,shell
|
||||
$ export MY_LOG_LEVEL='info'
|
||||
```
|
||||
|
||||
Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors
|
||||
or `auto` to enable them:
|
||||
|
||||
```no_run,shell
|
||||
$ export MY_LOG_STYLE=never
|
||||
```
|
||||
|
||||
If you want to control the logging output completely, see the `custom_logger` example.
|
||||
*/
|
||||
|
||||
#[cfg(all(feature = "color", feature = "humantime"))]
|
||||
fn main() {
|
||||
use env_logger::{fmt::Color, Builder, Env};
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
fn init_logger() {
|
||||
let env = Env::default()
|
||||
.filter("MY_LOG_LEVEL")
|
||||
.write_style("MY_LOG_STYLE");
|
||||
|
||||
Builder::from_env(env)
|
||||
.format(|buf, record| {
|
||||
let mut style = buf.style();
|
||||
style.set_bg(Color::Yellow).set_bold(true);
|
||||
|
||||
let timestamp = buf.timestamp();
|
||||
|
||||
writeln!(
|
||||
buf,
|
||||
"My formatted log ({}): {}",
|
||||
timestamp,
|
||||
style.value(record.args())
|
||||
)
|
||||
})
|
||||
.init();
|
||||
}
|
||||
|
||||
init_logger();
|
||||
|
||||
log::info!("a log from `MyLogger`");
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "color", feature = "humantime")))]
|
||||
fn main() {}
|
||||
59
third-party/vendor/env_logger/examples/custom_logger.rs
vendored
Normal file
59
third-party/vendor/env_logger/examples/custom_logger.rs
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*!
|
||||
Using `env_logger` to drive a custom logger.
|
||||
|
||||
Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
|
||||
|
||||
```no_run,shell
|
||||
$ export MY_LOG_LEVEL='info'
|
||||
```
|
||||
|
||||
If you only want to change the way logs are formatted, look at the `custom_format` example.
|
||||
*/
|
||||
|
||||
use env_logger::filter::{Builder, Filter};
|
||||
|
||||
use log::{info, Log, Metadata, Record, SetLoggerError};
|
||||
|
||||
const FILTER_ENV: &str = "MY_LOG_LEVEL";
|
||||
|
||||
struct MyLogger {
|
||||
inner: Filter,
|
||||
}
|
||||
|
||||
impl MyLogger {
|
||||
fn new() -> MyLogger {
|
||||
let mut builder = Builder::from_env(FILTER_ENV);
|
||||
|
||||
MyLogger {
|
||||
inner: builder.build(),
|
||||
}
|
||||
}
|
||||
|
||||
fn init() -> Result<(), SetLoggerError> {
|
||||
let logger = Self::new();
|
||||
|
||||
log::set_max_level(logger.inner.filter());
|
||||
log::set_boxed_logger(Box::new(logger))
|
||||
}
|
||||
}
|
||||
|
||||
impl Log for MyLogger {
|
||||
fn enabled(&self, metadata: &Metadata) -> bool {
|
||||
self.inner.enabled(metadata)
|
||||
}
|
||||
|
||||
fn log(&self, record: &Record) {
|
||||
// Check if the record is matched by the logger before logging
|
||||
if self.inner.matches(record) {
|
||||
println!("{} - {}", record.level(), record.args());
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
MyLogger::init().unwrap();
|
||||
|
||||
info!("a log from `MyLogger`");
|
||||
}
|
||||
37
third-party/vendor/env_logger/examples/default.rs
vendored
Normal file
37
third-party/vendor/env_logger/examples/default.rs
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*!
|
||||
Using `env_logger`.
|
||||
|
||||
Before running this example, try setting the `MY_LOG_LEVEL` environment variable to `info`:
|
||||
|
||||
```no_run,shell
|
||||
$ export MY_LOG_LEVEL='info'
|
||||
```
|
||||
|
||||
Also try setting the `MY_LOG_STYLE` environment variable to `never` to disable colors
|
||||
or `auto` to enable them:
|
||||
|
||||
```no_run,shell
|
||||
$ export MY_LOG_STYLE=never
|
||||
```
|
||||
*/
|
||||
|
||||
use log::{debug, error, info, trace, warn};
|
||||
|
||||
use env_logger::Env;
|
||||
|
||||
fn main() {
|
||||
// The `Env` lets us tweak what the environment
|
||||
// variables to read are and what the default
|
||||
// value is if they're missing
|
||||
let env = Env::default()
|
||||
.filter_or("MY_LOG_LEVEL", "trace")
|
||||
.write_style_or("MY_LOG_STYLE", "always");
|
||||
|
||||
env_logger::init_from_env(env);
|
||||
|
||||
trace!("some trace log");
|
||||
debug!("some debug log");
|
||||
info!("some information log");
|
||||
warn!("some warning log");
|
||||
error!("some error log");
|
||||
}
|
||||
39
third-party/vendor/env_logger/examples/direct_logger.rs
vendored
Normal file
39
third-party/vendor/env_logger/examples/direct_logger.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*!
|
||||
Using `env_logger::Logger` and the `log::Log` trait directly.
|
||||
|
||||
This example doesn't rely on environment variables, or having a static logger installed.
|
||||
*/
|
||||
|
||||
use env_logger::{Builder, WriteStyle};
|
||||
|
||||
use log::{Level, LevelFilter, Log, MetadataBuilder, Record};
|
||||
|
||||
fn record() -> Record<'static> {
|
||||
let error_metadata = MetadataBuilder::new()
|
||||
.target("myApp")
|
||||
.level(Level::Error)
|
||||
.build();
|
||||
|
||||
Record::builder()
|
||||
.metadata(error_metadata)
|
||||
.args(format_args!("Error!"))
|
||||
.line(Some(433))
|
||||
.file(Some("app.rs"))
|
||||
.module_path(Some("server"))
|
||||
.build()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let stylish_logger = Builder::new()
|
||||
.filter(None, LevelFilter::Error)
|
||||
.write_style(WriteStyle::Always)
|
||||
.build();
|
||||
|
||||
let unstylish_logger = Builder::new()
|
||||
.filter(None, LevelFilter::Error)
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
stylish_logger.log(&record());
|
||||
unstylish_logger.log(&record());
|
||||
}
|
||||
17
third-party/vendor/env_logger/examples/filters_from_code.rs
vendored
Normal file
17
third-party/vendor/env_logger/examples/filters_from_code.rs
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/*!
|
||||
Specify logging filters in code instead of using an environment variable.
|
||||
*/
|
||||
|
||||
use env_logger::Builder;
|
||||
|
||||
use log::{debug, error, info, trace, warn, LevelFilter};
|
||||
|
||||
fn main() {
|
||||
Builder::new().filter_level(LevelFilter::max()).init();
|
||||
|
||||
trace!("some trace log");
|
||||
debug!("some debug log");
|
||||
info!("some information log");
|
||||
warn!("some warning log");
|
||||
error!("some error log");
|
||||
}
|
||||
53
third-party/vendor/env_logger/examples/in_tests.rs
vendored
Normal file
53
third-party/vendor/env_logger/examples/in_tests.rs
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*!
|
||||
Using `env_logger` in tests.
|
||||
|
||||
Log events will be captured by `cargo` and only printed if the test fails.
|
||||
You can run this example by calling:
|
||||
|
||||
```text
|
||||
cargo test --example in_tests
|
||||
```
|
||||
|
||||
You should see the `it_does_not_work` test fail and include its log output.
|
||||
*/
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use log::debug;
|
||||
|
||||
fn init_logger() {
|
||||
let _ = env_logger::builder()
|
||||
// Include all events in tests
|
||||
.filter_level(log::LevelFilter::max())
|
||||
// Ensure events are captured by `cargo test`
|
||||
.is_test(true)
|
||||
// Ignore errors initializing the logger if tests race to configure it
|
||||
.try_init();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
init_logger();
|
||||
|
||||
let a = 1;
|
||||
let b = 2;
|
||||
|
||||
debug!("checking whether {} + {} = 3", a, b);
|
||||
|
||||
assert_eq!(3, a + b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_does_not_work() {
|
||||
init_logger();
|
||||
|
||||
let a = 1;
|
||||
let b = 2;
|
||||
|
||||
debug!("checking whether {} + {} = 6", a, b);
|
||||
|
||||
assert_eq!(6, a + b);
|
||||
}
|
||||
}
|
||||
24
third-party/vendor/env_logger/examples/syslog_friendly_format.rs
vendored
Normal file
24
third-party/vendor/env_logger/examples/syslog_friendly_format.rs
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
match std::env::var("RUST_LOG_STYLE") {
|
||||
Ok(s) if s == "SYSTEMD" => env_logger::builder()
|
||||
.format(|buf, record| {
|
||||
writeln!(
|
||||
buf,
|
||||
"<{}>{}: {}",
|
||||
match record.level() {
|
||||
log::Level::Error => 3,
|
||||
log::Level::Warn => 4,
|
||||
log::Level::Info => 6,
|
||||
log::Level::Debug => 7,
|
||||
log::Level::Trace => 7,
|
||||
},
|
||||
record.target(),
|
||||
record.args()
|
||||
)
|
||||
})
|
||||
.init(),
|
||||
_ => env_logger::init(),
|
||||
};
|
||||
}
|
||||
879
third-party/vendor/env_logger/src/filter/mod.rs
vendored
Normal file
879
third-party/vendor/env_logger/src/filter/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,879 @@
|
|||
//! Filtering for log records.
|
||||
//!
|
||||
//! This module contains the log filtering used by `env_logger` to match records.
|
||||
//! You can use the `Filter` type in your own logger implementation to use the same
|
||||
//! filter parsing and matching as `env_logger`. For more details about the format
|
||||
//! for directive strings see [Enabling Logging].
|
||||
//!
|
||||
//! ## Using `env_logger` in your own logger
|
||||
//!
|
||||
//! You can use `env_logger`'s filtering functionality with your own logger.
|
||||
//! Call [`Builder::parse`] to parse directives from a string when constructing
|
||||
//! your logger. Call [`Filter::matches`] to check whether a record should be
|
||||
//! logged based on the parsed filters when log records are received.
|
||||
//!
|
||||
//! ```
|
||||
//! extern crate log;
|
||||
//! extern crate env_logger;
|
||||
//! use env_logger::filter::Filter;
|
||||
//! use log::{Log, Metadata, Record};
|
||||
//!
|
||||
//! struct MyLogger {
|
||||
//! filter: Filter
|
||||
//! }
|
||||
//!
|
||||
//! impl MyLogger {
|
||||
//! fn new() -> MyLogger {
|
||||
//! use env_logger::filter::Builder;
|
||||
//! let mut builder = Builder::new();
|
||||
//!
|
||||
//! // Parse a directives string from an environment variable
|
||||
//! if let Ok(ref filter) = std::env::var("MY_LOG_LEVEL") {
|
||||
//! builder.parse(filter);
|
||||
//! }
|
||||
//!
|
||||
//! MyLogger {
|
||||
//! filter: builder.build()
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! impl Log for MyLogger {
|
||||
//! fn enabled(&self, metadata: &Metadata) -> bool {
|
||||
//! self.filter.enabled(metadata)
|
||||
//! }
|
||||
//!
|
||||
//! fn log(&self, record: &Record) {
|
||||
//! // Check if the record is matched by the filter
|
||||
//! if self.filter.matches(record) {
|
||||
//! println!("{:?}", record);
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! fn flush(&self) {}
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [Enabling Logging]: ../index.html#enabling-logging
|
||||
//! [`Builder::parse`]: struct.Builder.html#method.parse
|
||||
//! [`Filter::matches`]: struct.Filter.html#method.matches
|
||||
|
||||
use log::{Level, LevelFilter, Metadata, Record};
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
|
||||
#[cfg(feature = "regex")]
|
||||
#[path = "regex.rs"]
|
||||
mod inner;
|
||||
|
||||
#[cfg(not(feature = "regex"))]
|
||||
#[path = "string.rs"]
|
||||
mod inner;
|
||||
|
||||
/// A builder for a log filter.
|
||||
///
|
||||
/// It can be used to parse a set of directives from a string before building
|
||||
/// a [`Filter`] instance.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// # #[macro_use] extern crate log;
|
||||
/// # use std::env;
|
||||
/// use env_logger::filter::Builder;
|
||||
///
|
||||
/// let mut builder = Builder::new();
|
||||
///
|
||||
/// // Parse a logging filter from an environment variable.
|
||||
/// if let Ok(rust_log) = env::var("RUST_LOG") {
|
||||
/// builder.parse(&rust_log);
|
||||
/// }
|
||||
///
|
||||
/// let filter = builder.build();
|
||||
/// ```
|
||||
///
|
||||
/// [`Filter`]: struct.Filter.html
|
||||
pub struct Builder {
|
||||
directives: Vec<Directive>,
|
||||
filter: Option<inner::Filter>,
|
||||
built: bool,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Initializes the filter builder with defaults.
|
||||
pub fn new() -> Builder {
|
||||
Builder {
|
||||
directives: Vec::new(),
|
||||
filter: None,
|
||||
built: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the filter builder from an environment.
|
||||
pub fn from_env(env: &str) -> Builder {
|
||||
let mut builder = Builder::new();
|
||||
|
||||
if let Ok(s) = env::var(env) {
|
||||
builder.parse(&s);
|
||||
}
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
/// Insert the directive replacing any directive with the same name.
|
||||
fn insert_directive(&mut self, mut directive: Directive) {
|
||||
if let Some(pos) = self
|
||||
.directives
|
||||
.iter()
|
||||
.position(|d| d.name == directive.name)
|
||||
{
|
||||
mem::swap(&mut self.directives[pos], &mut directive);
|
||||
} else {
|
||||
self.directives.push(directive);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a directive to the filter for a specific module.
|
||||
pub fn filter_module(&mut self, module: &str, level: LevelFilter) -> &mut Self {
|
||||
self.filter(Some(module), level)
|
||||
}
|
||||
|
||||
/// Adds a directive to the filter for all modules.
|
||||
pub fn filter_level(&mut self, level: LevelFilter) -> &mut Self {
|
||||
self.filter(None, level)
|
||||
}
|
||||
|
||||
/// Adds a directive to the filter.
|
||||
///
|
||||
/// The given module (if any) will log at most the specified level provided.
|
||||
/// If no module is provided then the filter will apply to all log messages.
|
||||
pub fn filter(&mut self, module: Option<&str>, level: LevelFilter) -> &mut Self {
|
||||
self.insert_directive(Directive {
|
||||
name: module.map(|s| s.to_string()),
|
||||
level,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Parses the directives string.
|
||||
///
|
||||
/// See the [Enabling Logging] section for more details.
|
||||
///
|
||||
/// [Enabling Logging]: ../index.html#enabling-logging
|
||||
pub fn parse(&mut self, filters: &str) -> &mut Self {
|
||||
let (directives, filter) = parse_spec(filters);
|
||||
|
||||
self.filter = filter;
|
||||
|
||||
for directive in directives {
|
||||
self.insert_directive(directive);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Build a log filter.
|
||||
pub fn build(&mut self) -> Filter {
|
||||
assert!(!self.built, "attempt to re-use consumed builder");
|
||||
self.built = true;
|
||||
|
||||
let mut directives = Vec::new();
|
||||
if self.directives.is_empty() {
|
||||
// Adds the default filter if none exist
|
||||
directives.push(Directive {
|
||||
name: None,
|
||||
level: LevelFilter::Error,
|
||||
});
|
||||
} else {
|
||||
// Consume directives.
|
||||
directives = mem::take(&mut self.directives);
|
||||
// Sort the directives by length of their name, this allows a
|
||||
// little more efficient lookup at runtime.
|
||||
directives.sort_by(|a, b| {
|
||||
let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0);
|
||||
let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0);
|
||||
alen.cmp(&blen)
|
||||
});
|
||||
}
|
||||
|
||||
Filter {
|
||||
directives: mem::take(&mut directives),
|
||||
filter: mem::take(&mut self.filter),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
fn default() -> Self {
|
||||
Builder::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Builder {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.built {
|
||||
f.debug_struct("Filter").field("built", &true).finish()
|
||||
} else {
|
||||
f.debug_struct("Filter")
|
||||
.field("filter", &self.filter)
|
||||
.field("directives", &self.directives)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Directive {
|
||||
name: Option<String>,
|
||||
level: LevelFilter,
|
||||
}
|
||||
|
||||
/// A log filter.
|
||||
///
|
||||
/// This struct can be used to determine whether or not a log record
|
||||
/// should be written to the output.
|
||||
/// Use the [`Builder`] type to parse and construct a `Filter`.
|
||||
///
|
||||
/// [`Builder`]: struct.Builder.html
|
||||
pub struct Filter {
|
||||
directives: Vec<Directive>,
|
||||
filter: Option<inner::Filter>,
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
/// Returns the maximum `LevelFilter` that this filter instance is
|
||||
/// configured to output.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use log::LevelFilter;
|
||||
/// use env_logger::filter::Builder;
|
||||
///
|
||||
/// let mut builder = Builder::new();
|
||||
/// builder.filter(Some("module1"), LevelFilter::Info);
|
||||
/// builder.filter(Some("module2"), LevelFilter::Error);
|
||||
///
|
||||
/// let filter = builder.build();
|
||||
/// assert_eq!(filter.filter(), LevelFilter::Info);
|
||||
/// ```
|
||||
pub fn filter(&self) -> LevelFilter {
|
||||
self.directives
|
||||
.iter()
|
||||
.map(|d| d.level)
|
||||
.max()
|
||||
.unwrap_or(LevelFilter::Off)
|
||||
}
|
||||
|
||||
/// Checks if this record matches the configured filter.
|
||||
pub fn matches(&self, record: &Record) -> bool {
|
||||
if !self.enabled(record.metadata()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(filter) = self.filter.as_ref() {
|
||||
if !filter.is_match(&record.args().to_string()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Determines if a log message with the specified metadata would be logged.
|
||||
pub fn enabled(&self, metadata: &Metadata) -> bool {
|
||||
let level = metadata.level();
|
||||
let target = metadata.target();
|
||||
|
||||
enabled(&self.directives, level, target)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Filter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Filter")
|
||||
.field("filter", &self.filter)
|
||||
.field("directives", &self.directives)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=error/foo")
|
||||
/// and return a vector with log directives.
|
||||
fn parse_spec(spec: &str) -> (Vec<Directive>, Option<inner::Filter>) {
|
||||
let mut dirs = Vec::new();
|
||||
|
||||
let mut parts = spec.split('/');
|
||||
let mods = parts.next();
|
||||
let filter = parts.next();
|
||||
if parts.next().is_some() {
|
||||
eprintln!(
|
||||
"warning: invalid logging spec '{}', \
|
||||
ignoring it (too many '/'s)",
|
||||
spec
|
||||
);
|
||||
return (dirs, None);
|
||||
}
|
||||
if let Some(m) = mods {
|
||||
for s in m.split(',').map(|ss| ss.trim()) {
|
||||
if s.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut parts = s.split('=');
|
||||
let (log_level, name) =
|
||||
match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
|
||||
(Some(part0), None, None) => {
|
||||
// if the single argument is a log-level string or number,
|
||||
// treat that as a global fallback
|
||||
match part0.parse() {
|
||||
Ok(num) => (num, None),
|
||||
Err(_) => (LevelFilter::max(), Some(part0)),
|
||||
}
|
||||
}
|
||||
(Some(part0), Some(""), None) => (LevelFilter::max(), Some(part0)),
|
||||
(Some(part0), Some(part1), None) => match part1.parse() {
|
||||
Ok(num) => (num, Some(part0)),
|
||||
_ => {
|
||||
eprintln!(
|
||||
"warning: invalid logging spec '{}', \
|
||||
ignoring it",
|
||||
part1
|
||||
);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
eprintln!(
|
||||
"warning: invalid logging spec '{}', \
|
||||
ignoring it",
|
||||
s
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
dirs.push(Directive {
|
||||
name: name.map(|s| s.to_string()),
|
||||
level: log_level,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let filter = filter.and_then(|filter| match inner::Filter::new(filter) {
|
||||
Ok(re) => Some(re),
|
||||
Err(e) => {
|
||||
eprintln!("warning: invalid regex filter - {}", e);
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
(dirs, filter)
|
||||
}
|
||||
|
||||
// Check whether a level and target are enabled by the set of directives.
|
||||
fn enabled(directives: &[Directive], level: Level, target: &str) -> bool {
|
||||
// Search for the longest match, the vector is assumed to be pre-sorted.
|
||||
for directive in directives.iter().rev() {
|
||||
match directive.name {
|
||||
Some(ref name) if !target.starts_with(&**name) => {}
|
||||
Some(..) | None => return level <= directive.level,
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use log::{Level, LevelFilter};
|
||||
|
||||
use super::{enabled, parse_spec, Builder, Directive, Filter};
|
||||
|
||||
fn make_logger_filter(dirs: Vec<Directive>) -> Filter {
|
||||
let mut logger = Builder::new().build();
|
||||
logger.directives = dirs;
|
||||
logger
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_info() {
|
||||
let logger = Builder::new().filter(None, LevelFilter::Info).build();
|
||||
assert!(enabled(&logger.directives, Level::Info, "crate1"));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, "crate1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_beginning_longest_match() {
|
||||
let logger = Builder::new()
|
||||
.filter(Some("crate2"), LevelFilter::Info)
|
||||
.filter(Some("crate2::mod"), LevelFilter::Debug)
|
||||
.filter(Some("crate1::mod1"), LevelFilter::Warn)
|
||||
.build();
|
||||
assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
|
||||
}
|
||||
|
||||
// Some of our tests are only correct or complete when they cover the full
|
||||
// universe of variants for log::Level. In the unlikely event that a new
|
||||
// variant is added in the future, this test will detect the scenario and
|
||||
// alert us to the need to review and update the tests. In such a
|
||||
// situation, this test will fail to compile, and the error message will
|
||||
// look something like this:
|
||||
//
|
||||
// error[E0004]: non-exhaustive patterns: `NewVariant` not covered
|
||||
// --> src/filter/mod.rs:413:15
|
||||
// |
|
||||
// 413 | match level_universe {
|
||||
// | ^^^^^^^^^^^^^^ pattern `NewVariant` not covered
|
||||
#[test]
|
||||
fn ensure_tests_cover_level_universe() {
|
||||
let level_universe: Level = Level::Trace; // use of trace variant is arbitrary
|
||||
match level_universe {
|
||||
Level::Error | Level::Warn | Level::Info | Level::Debug | Level::Trace => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default() {
|
||||
let logger = Builder::new().parse("info,crate1::mod1=warn").build();
|
||||
assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
|
||||
assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_off_lc() {
|
||||
let logger = Builder::new().parse("off").build();
|
||||
assert!(!enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_off_uc() {
|
||||
let logger = Builder::new().parse("OFF").build();
|
||||
assert!(!enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_error_lc() {
|
||||
let logger = Builder::new().parse("error").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_error_uc() {
|
||||
let logger = Builder::new().parse("ERROR").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_warn_lc() {
|
||||
let logger = Builder::new().parse("warn").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_warn_uc() {
|
||||
let logger = Builder::new().parse("WARN").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_info_lc() {
|
||||
let logger = Builder::new().parse("info").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_info_uc() {
|
||||
let logger = Builder::new().parse("INFO").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_debug_lc() {
|
||||
let logger = Builder::new().parse("debug").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_debug_uc() {
|
||||
let logger = Builder::new().parse("DEBUG").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_trace_lc() {
|
||||
let logger = Builder::new().parse("trace").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_default_bare_level_trace_uc() {
|
||||
let logger = Builder::new().parse("TRACE").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
|
||||
// In practice, the desired log level is typically specified by a token
|
||||
// that is either all lowercase (e.g., 'trace') or all uppercase (.e.g,
|
||||
// 'TRACE'), but this tests serves as a reminder that
|
||||
// log::Level::from_str() ignores all case variants.
|
||||
#[test]
|
||||
fn parse_default_bare_level_debug_mixed() {
|
||||
{
|
||||
let logger = Builder::new().parse("Debug").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
{
|
||||
let logger = Builder::new().parse("debuG").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
{
|
||||
let logger = Builder::new().parse("deBug").build();
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
{
|
||||
let logger = Builder::new().parse("DeBuG").build(); // LaTeX flavor!
|
||||
assert!(enabled(&logger.directives, Level::Error, ""));
|
||||
assert!(enabled(&logger.directives, Level::Warn, ""));
|
||||
assert!(enabled(&logger.directives, Level::Info, ""));
|
||||
assert!(enabled(&logger.directives, Level::Debug, ""));
|
||||
assert!(!enabled(&logger.directives, Level::Trace, ""));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_full_path() {
|
||||
let logger = make_logger_filter(vec![
|
||||
Directive {
|
||||
name: Some("crate2".to_string()),
|
||||
level: LevelFilter::Info,
|
||||
},
|
||||
Directive {
|
||||
name: Some("crate1::mod1".to_string()),
|
||||
level: LevelFilter::Warn,
|
||||
},
|
||||
]);
|
||||
assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
|
||||
assert!(!enabled(&logger.directives, Level::Info, "crate1::mod1"));
|
||||
assert!(enabled(&logger.directives, Level::Info, "crate2"));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_match() {
|
||||
let logger = make_logger_filter(vec![
|
||||
Directive {
|
||||
name: Some("crate2".to_string()),
|
||||
level: LevelFilter::Info,
|
||||
},
|
||||
Directive {
|
||||
name: Some("crate1::mod1".to_string()),
|
||||
level: LevelFilter::Warn,
|
||||
},
|
||||
]);
|
||||
assert!(!enabled(&logger.directives, Level::Warn, "crate3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_beginning() {
|
||||
let logger = make_logger_filter(vec![
|
||||
Directive {
|
||||
name: Some("crate2".to_string()),
|
||||
level: LevelFilter::Info,
|
||||
},
|
||||
Directive {
|
||||
name: Some("crate1::mod1".to_string()),
|
||||
level: LevelFilter::Warn,
|
||||
},
|
||||
]);
|
||||
assert!(enabled(&logger.directives, Level::Info, "crate2::mod1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_beginning_longest_match() {
|
||||
let logger = make_logger_filter(vec![
|
||||
Directive {
|
||||
name: Some("crate2".to_string()),
|
||||
level: LevelFilter::Info,
|
||||
},
|
||||
Directive {
|
||||
name: Some("crate2::mod".to_string()),
|
||||
level: LevelFilter::Debug,
|
||||
},
|
||||
Directive {
|
||||
name: Some("crate1::mod1".to_string()),
|
||||
level: LevelFilter::Warn,
|
||||
},
|
||||
]);
|
||||
assert!(enabled(&logger.directives, Level::Debug, "crate2::mod1"));
|
||||
assert!(!enabled(&logger.directives, Level::Debug, "crate2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn match_default() {
|
||||
let logger = make_logger_filter(vec![
|
||||
Directive {
|
||||
name: None,
|
||||
level: LevelFilter::Info,
|
||||
},
|
||||
Directive {
|
||||
name: Some("crate1::mod1".to_string()),
|
||||
level: LevelFilter::Warn,
|
||||
},
|
||||
]);
|
||||
assert!(enabled(&logger.directives, Level::Warn, "crate1::mod1"));
|
||||
assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_level() {
|
||||
let logger = make_logger_filter(vec![
|
||||
Directive {
|
||||
name: None,
|
||||
level: LevelFilter::Info,
|
||||
},
|
||||
Directive {
|
||||
name: Some("crate1::mod1".to_string()),
|
||||
level: LevelFilter::Off,
|
||||
},
|
||||
]);
|
||||
assert!(!enabled(&logger.directives, Level::Error, "crate1::mod1"));
|
||||
assert!(enabled(&logger.directives, Level::Info, "crate2::mod2"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_valid() {
|
||||
let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug");
|
||||
assert_eq!(dirs.len(), 3);
|
||||
assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::Error);
|
||||
|
||||
assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
|
||||
assert_eq!(dirs[1].level, LevelFilter::max());
|
||||
|
||||
assert_eq!(dirs[2].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[2].level, LevelFilter::Debug);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_invalid_crate() {
|
||||
// test parse_spec with multiple = in specification
|
||||
let (dirs, filter) = parse_spec("crate1::mod1=warn=info,crate2=debug");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::Debug);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_invalid_level() {
|
||||
// test parse_spec with 'noNumber' as log level
|
||||
let (dirs, filter) = parse_spec("crate1::mod1=noNumber,crate2=debug");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::Debug);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_string_level() {
|
||||
// test parse_spec with 'warn' as log level
|
||||
let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2=warn");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::Warn);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_empty_level() {
|
||||
// test parse_spec with '' as log level
|
||||
let (dirs, filter) = parse_spec("crate1::mod1=wrong,crate2=");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::max());
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_empty_level_isolated() {
|
||||
// test parse_spec with "" as log level (and the entire spec str)
|
||||
let (dirs, filter) = parse_spec(""); // should be ignored
|
||||
assert_eq!(dirs.len(), 0);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_blank_level_isolated() {
|
||||
// test parse_spec with a white-space-only string specified as the log
|
||||
// level (and the entire spec str)
|
||||
let (dirs, filter) = parse_spec(" "); // should be ignored
|
||||
assert_eq!(dirs.len(), 0);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_blank_level_isolated_comma_only() {
|
||||
// The spec should contain zero or more comma-separated string slices,
|
||||
// so a comma-only string should be interpreted as two empty strings
|
||||
// (which should both be treated as invalid, so ignored).
|
||||
let (dirs, filter) = parse_spec(","); // should be ignored
|
||||
assert_eq!(dirs.len(), 0);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_blank_level_isolated_comma_blank() {
|
||||
// The spec should contain zero or more comma-separated string slices,
|
||||
// so this bogus spec should be interpreted as containing one empty
|
||||
// string and one blank string. Both should both be treated as
|
||||
// invalid, so ignored.
|
||||
let (dirs, filter) = parse_spec(", "); // should be ignored
|
||||
assert_eq!(dirs.len(), 0);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_blank_level_isolated_blank_comma() {
|
||||
// The spec should contain zero or more comma-separated string slices,
|
||||
// so this bogus spec should be interpreted as containing one blank
|
||||
// string and one empty string. Both should both be treated as
|
||||
// invalid, so ignored.
|
||||
let (dirs, filter) = parse_spec(" ,"); // should be ignored
|
||||
assert_eq!(dirs.len(), 0);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_global() {
|
||||
// test parse_spec with no crate
|
||||
let (dirs, filter) = parse_spec("warn,crate2=debug");
|
||||
assert_eq!(dirs.len(), 2);
|
||||
assert_eq!(dirs[0].name, None);
|
||||
assert_eq!(dirs[0].level, LevelFilter::Warn);
|
||||
assert_eq!(dirs[1].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[1].level, LevelFilter::Debug);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_global_bare_warn_lc() {
|
||||
// test parse_spec with no crate, in isolation, all lowercase
|
||||
let (dirs, filter) = parse_spec("warn");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, None);
|
||||
assert_eq!(dirs[0].level, LevelFilter::Warn);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_global_bare_warn_uc() {
|
||||
// test parse_spec with no crate, in isolation, all uppercase
|
||||
let (dirs, filter) = parse_spec("WARN");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, None);
|
||||
assert_eq!(dirs[0].level, LevelFilter::Warn);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_global_bare_warn_mixed() {
|
||||
// test parse_spec with no crate, in isolation, mixed case
|
||||
let (dirs, filter) = parse_spec("wArN");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, None);
|
||||
assert_eq!(dirs[0].level, LevelFilter::Warn);
|
||||
assert!(filter.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_valid_filter() {
|
||||
let (dirs, filter) = parse_spec("crate1::mod1=error,crate1::mod2,crate2=debug/abc");
|
||||
assert_eq!(dirs.len(), 3);
|
||||
assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::Error);
|
||||
|
||||
assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
|
||||
assert_eq!(dirs[1].level, LevelFilter::max());
|
||||
|
||||
assert_eq!(dirs[2].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[2].level, LevelFilter::Debug);
|
||||
assert!(filter.is_some() && filter.unwrap().to_string() == "abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_invalid_crate_filter() {
|
||||
let (dirs, filter) = parse_spec("crate1::mod1=error=warn,crate2=debug/a.c");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, Some("crate2".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::Debug);
|
||||
assert!(filter.is_some() && filter.unwrap().to_string() == "a.c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_spec_empty_with_filter() {
|
||||
let (dirs, filter) = parse_spec("crate1/a*c");
|
||||
assert_eq!(dirs.len(), 1);
|
||||
assert_eq!(dirs[0].name, Some("crate1".to_string()));
|
||||
assert_eq!(dirs[0].level, LevelFilter::max());
|
||||
assert!(filter.is_some() && filter.unwrap().to_string() == "a*c");
|
||||
}
|
||||
}
|
||||
29
third-party/vendor/env_logger/src/filter/regex.rs
vendored
Normal file
29
third-party/vendor/env_logger/src/filter/regex.rs
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
extern crate regex;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use self::regex::Regex;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Filter {
|
||||
inner: Regex,
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub fn new(spec: &str) -> Result<Filter, String> {
|
||||
match Regex::new(spec) {
|
||||
Ok(r) => Ok(Filter { inner: r }),
|
||||
Err(e) => Err(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_match(&self, s: &str) -> bool {
|
||||
self.inner.is_match(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Filter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
24
third-party/vendor/env_logger/src/filter/string.rs
vendored
Normal file
24
third-party/vendor/env_logger/src/filter/string.rs
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Filter {
|
||||
inner: String,
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub fn new(spec: &str) -> Result<Filter, String> {
|
||||
Ok(Filter {
|
||||
inner: spec.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn is_match(&self, s: &str) -> bool {
|
||||
s.contains(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Filter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
114
third-party/vendor/env_logger/src/fmt/humantime.rs
vendored
Normal file
114
third-party/vendor/env_logger/src/fmt/humantime.rs
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
use std::fmt;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use humantime::{
|
||||
format_rfc3339_micros, format_rfc3339_millis, format_rfc3339_nanos, format_rfc3339_seconds,
|
||||
};
|
||||
|
||||
use crate::fmt::{Formatter, TimestampPrecision};
|
||||
|
||||
impl Formatter {
|
||||
/// Get a [`Timestamp`] for the current date and time in UTC.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Include the current timestamp with the log record:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let ts = buf.timestamp();
|
||||
///
|
||||
/// writeln!(buf, "{}: {}: {}", ts, record.level(), record.args())
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// [`Timestamp`]: struct.Timestamp.html
|
||||
pub fn timestamp(&self) -> Timestamp {
|
||||
Timestamp {
|
||||
time: SystemTime::now(),
|
||||
precision: TimestampPrecision::Seconds,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a [`Timestamp`] for the current date and time in UTC with full
|
||||
/// second precision.
|
||||
pub fn timestamp_seconds(&self) -> Timestamp {
|
||||
Timestamp {
|
||||
time: SystemTime::now(),
|
||||
precision: TimestampPrecision::Seconds,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a [`Timestamp`] for the current date and time in UTC with
|
||||
/// millisecond precision.
|
||||
pub fn timestamp_millis(&self) -> Timestamp {
|
||||
Timestamp {
|
||||
time: SystemTime::now(),
|
||||
precision: TimestampPrecision::Millis,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a [`Timestamp`] for the current date and time in UTC with
|
||||
/// microsecond precision.
|
||||
pub fn timestamp_micros(&self) -> Timestamp {
|
||||
Timestamp {
|
||||
time: SystemTime::now(),
|
||||
precision: TimestampPrecision::Micros,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a [`Timestamp`] for the current date and time in UTC with
|
||||
/// nanosecond precision.
|
||||
pub fn timestamp_nanos(&self) -> Timestamp {
|
||||
Timestamp {
|
||||
time: SystemTime::now(),
|
||||
precision: TimestampPrecision::Nanos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An [RFC3339] formatted timestamp.
|
||||
///
|
||||
/// The timestamp implements [`Display`] and can be written to a [`Formatter`].
|
||||
///
|
||||
/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt
|
||||
/// [`Display`]: https://doc.rust-lang.org/stable/std/fmt/trait.Display.html
|
||||
/// [`Formatter`]: struct.Formatter.html
|
||||
pub struct Timestamp {
|
||||
time: SystemTime,
|
||||
precision: TimestampPrecision,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Timestamp {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
/// A `Debug` wrapper for `Timestamp` that uses the `Display` implementation.
|
||||
struct TimestampValue<'a>(&'a Timestamp);
|
||||
|
||||
impl<'a> fmt::Debug for TimestampValue<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
f.debug_tuple("Timestamp")
|
||||
.field(&TimestampValue(self))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Timestamp {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let formatter = match self.precision {
|
||||
TimestampPrecision::Seconds => format_rfc3339_seconds,
|
||||
TimestampPrecision::Millis => format_rfc3339_millis,
|
||||
TimestampPrecision::Micros => format_rfc3339_micros,
|
||||
TimestampPrecision::Nanos => format_rfc3339_nanos,
|
||||
};
|
||||
|
||||
formatter(self.time).fmt(f)
|
||||
}
|
||||
}
|
||||
717
third-party/vendor/env_logger/src/fmt/mod.rs
vendored
Normal file
717
third-party/vendor/env_logger/src/fmt/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,717 @@
|
|||
//! Formatting for log records.
|
||||
//!
|
||||
//! This module contains a [`Formatter`] that can be used to format log records
|
||||
//! into without needing temporary allocations. Usually you won't need to worry
|
||||
//! about the contents of this module and can use the `Formatter` like an ordinary
|
||||
//! [`Write`].
|
||||
//!
|
||||
//! # Formatting log records
|
||||
//!
|
||||
//! The format used to print log records can be customised using the [`Builder::format`]
|
||||
//! method.
|
||||
//! Custom formats can apply different color and weight to printed values using
|
||||
//! [`Style`] builders.
|
||||
//!
|
||||
//! ```
|
||||
//! use std::io::Write;
|
||||
//!
|
||||
//! let mut builder = env_logger::Builder::new();
|
||||
//!
|
||||
//! builder.format(|buf, record| {
|
||||
//! writeln!(buf, "{}: {}",
|
||||
//! record.level(),
|
||||
//! record.args())
|
||||
//! });
|
||||
//! ```
|
||||
//!
|
||||
//! [`Formatter`]: struct.Formatter.html
|
||||
//! [`Style`]: struct.Style.html
|
||||
//! [`Builder::format`]: ../struct.Builder.html#method.format
|
||||
//! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::io::prelude::*;
|
||||
use std::rc::Rc;
|
||||
use std::{fmt, io, mem};
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
use log::Level;
|
||||
use log::Record;
|
||||
|
||||
#[cfg(feature = "humantime")]
|
||||
mod humantime;
|
||||
pub(crate) mod writer;
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
mod style;
|
||||
#[cfg(feature = "color")]
|
||||
pub use style::{Color, Style, StyledValue};
|
||||
|
||||
#[cfg(feature = "humantime")]
|
||||
pub use self::humantime::Timestamp;
|
||||
pub use self::writer::glob::*;
|
||||
|
||||
use self::writer::{Buffer, Writer};
|
||||
|
||||
pub(crate) mod glob {
|
||||
pub use super::{Target, TimestampPrecision, WriteStyle};
|
||||
}
|
||||
|
||||
/// Formatting precision of timestamps.
|
||||
///
|
||||
/// Seconds give precision of full seconds, milliseconds give thousands of a
|
||||
/// second (3 decimal digits), microseconds are millionth of a second (6 decimal
|
||||
/// digits) and nanoseconds are billionth of a second (9 decimal digits).
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum TimestampPrecision {
|
||||
/// Full second precision (0 decimal digits)
|
||||
Seconds,
|
||||
/// Millisecond precision (3 decimal digits)
|
||||
Millis,
|
||||
/// Microsecond precision (6 decimal digits)
|
||||
Micros,
|
||||
/// Nanosecond precision (9 decimal digits)
|
||||
Nanos,
|
||||
}
|
||||
|
||||
/// The default timestamp precision is seconds.
|
||||
impl Default for TimestampPrecision {
|
||||
fn default() -> Self {
|
||||
TimestampPrecision::Seconds
|
||||
}
|
||||
}
|
||||
|
||||
/// A formatter to write logs into.
|
||||
///
|
||||
/// `Formatter` implements the standard [`Write`] trait for writing log records.
|
||||
/// It also supports terminal colors, through the [`style`] method.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Use the [`writeln`] macro to format a log record.
|
||||
/// An instance of a `Formatter` is passed to an `env_logger` format as `buf`:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()));
|
||||
/// ```
|
||||
///
|
||||
/// [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
|
||||
/// [`writeln`]: https://doc.rust-lang.org/stable/std/macro.writeln.html
|
||||
/// [`style`]: #method.style
|
||||
pub struct Formatter {
|
||||
buf: Rc<RefCell<Buffer>>,
|
||||
write_style: WriteStyle,
|
||||
}
|
||||
|
||||
impl Formatter {
|
||||
pub(crate) fn new(writer: &Writer) -> Self {
|
||||
Formatter {
|
||||
buf: Rc::new(RefCell::new(writer.buffer())),
|
||||
write_style: writer.write_style(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn write_style(&self) -> WriteStyle {
|
||||
self.write_style
|
||||
}
|
||||
|
||||
pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
|
||||
writer.print(&self.buf.borrow())
|
||||
}
|
||||
|
||||
pub(crate) fn clear(&mut self) {
|
||||
self.buf.borrow_mut().clear()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
impl Formatter {
|
||||
/// Begin a new [`Style`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a bold, red colored style and use it to print the log level:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
/// use env_logger::fmt::Color;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut level_style = buf.style();
|
||||
///
|
||||
/// level_style.set_color(Color::Red).set_bold(true);
|
||||
///
|
||||
/// writeln!(buf, "{}: {}",
|
||||
/// level_style.value(record.level()),
|
||||
/// record.args())
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// [`Style`]: struct.Style.html
|
||||
pub fn style(&self) -> Style {
|
||||
Style {
|
||||
buf: self.buf.clone(),
|
||||
spec: termcolor::ColorSpec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default [`Style`] for the given level.
|
||||
///
|
||||
/// The style can be used to print other values besides the level.
|
||||
pub fn default_level_style(&self, level: Level) -> Style {
|
||||
let mut level_style = self.style();
|
||||
match level {
|
||||
Level::Trace => level_style.set_color(Color::Cyan),
|
||||
Level::Debug => level_style.set_color(Color::Blue),
|
||||
Level::Info => level_style.set_color(Color::Green),
|
||||
Level::Warn => level_style.set_color(Color::Yellow),
|
||||
Level::Error => level_style.set_color(Color::Red).set_bold(true),
|
||||
};
|
||||
level_style
|
||||
}
|
||||
|
||||
/// Get a printable [`Style`] for the given level.
|
||||
///
|
||||
/// The style can only be used to print the level.
|
||||
pub fn default_styled_level(&self, level: Level) -> StyledValue<'static, Level> {
|
||||
self.default_level_style(level).into_value(level)
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Formatter {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.buf.borrow_mut().write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.buf.borrow_mut().flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Formatter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Formatter").finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>;
|
||||
|
||||
pub(crate) struct Builder {
|
||||
pub format_timestamp: Option<TimestampPrecision>,
|
||||
pub format_module_path: bool,
|
||||
pub format_target: bool,
|
||||
pub format_level: bool,
|
||||
pub format_indent: Option<usize>,
|
||||
pub custom_format: Option<FormatFn>,
|
||||
pub format_suffix: &'static str,
|
||||
built: bool,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Convert the format into a callable function.
|
||||
///
|
||||
/// If the `custom_format` is `Some`, then any `default_format` switches are ignored.
|
||||
/// If the `custom_format` is `None`, then a default format is returned.
|
||||
/// Any `default_format` switches set to `false` won't be written by the format.
|
||||
pub fn build(&mut self) -> FormatFn {
|
||||
assert!(!self.built, "attempt to re-use consumed builder");
|
||||
|
||||
let built = mem::replace(
|
||||
self,
|
||||
Builder {
|
||||
built: true,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
if let Some(fmt) = built.custom_format {
|
||||
fmt
|
||||
} else {
|
||||
Box::new(move |buf, record| {
|
||||
let fmt = DefaultFormat {
|
||||
timestamp: built.format_timestamp,
|
||||
module_path: built.format_module_path,
|
||||
target: built.format_target,
|
||||
level: built.format_level,
|
||||
written_header_value: false,
|
||||
indent: built.format_indent,
|
||||
suffix: built.format_suffix,
|
||||
buf,
|
||||
};
|
||||
|
||||
fmt.write(record)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
fn default() -> Self {
|
||||
Builder {
|
||||
format_timestamp: Some(Default::default()),
|
||||
format_module_path: false,
|
||||
format_target: true,
|
||||
format_level: true,
|
||||
format_indent: Some(4),
|
||||
custom_format: None,
|
||||
format_suffix: "\n",
|
||||
built: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
type SubtleStyle = StyledValue<'static, &'static str>;
|
||||
#[cfg(not(feature = "color"))]
|
||||
type SubtleStyle = &'static str;
|
||||
|
||||
/// The default format.
|
||||
///
|
||||
/// This format needs to work with any combination of crate features.
|
||||
struct DefaultFormat<'a> {
|
||||
timestamp: Option<TimestampPrecision>,
|
||||
module_path: bool,
|
||||
target: bool,
|
||||
level: bool,
|
||||
written_header_value: bool,
|
||||
indent: Option<usize>,
|
||||
buf: &'a mut Formatter,
|
||||
suffix: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> DefaultFormat<'a> {
|
||||
fn write(mut self, record: &Record) -> io::Result<()> {
|
||||
self.write_timestamp()?;
|
||||
self.write_level(record)?;
|
||||
self.write_module_path(record)?;
|
||||
self.write_target(record)?;
|
||||
self.finish_header()?;
|
||||
|
||||
self.write_args(record)
|
||||
}
|
||||
|
||||
fn subtle_style(&self, text: &'static str) -> SubtleStyle {
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
self.buf
|
||||
.style()
|
||||
.set_color(Color::Black)
|
||||
.set_intense(true)
|
||||
.clone()
|
||||
.into_value(text)
|
||||
}
|
||||
#[cfg(not(feature = "color"))]
|
||||
{
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
if !self.written_header_value {
|
||||
self.written_header_value = true;
|
||||
|
||||
let open_brace = self.subtle_style("[");
|
||||
write!(self.buf, "{}{}", open_brace, value)
|
||||
} else {
|
||||
write!(self.buf, " {}", value)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_level(&mut self, record: &Record) -> io::Result<()> {
|
||||
if !self.level {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let level = {
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
self.buf.default_styled_level(record.level())
|
||||
}
|
||||
#[cfg(not(feature = "color"))]
|
||||
{
|
||||
record.level()
|
||||
}
|
||||
};
|
||||
|
||||
self.write_header_value(format_args!("{:<5}", level))
|
||||
}
|
||||
|
||||
fn write_timestamp(&mut self) -> io::Result<()> {
|
||||
#[cfg(feature = "humantime")]
|
||||
{
|
||||
use self::TimestampPrecision::*;
|
||||
let ts = match self.timestamp {
|
||||
None => return Ok(()),
|
||||
Some(Seconds) => self.buf.timestamp_seconds(),
|
||||
Some(Millis) => self.buf.timestamp_millis(),
|
||||
Some(Micros) => self.buf.timestamp_micros(),
|
||||
Some(Nanos) => self.buf.timestamp_nanos(),
|
||||
};
|
||||
|
||||
self.write_header_value(ts)
|
||||
}
|
||||
#[cfg(not(feature = "humantime"))]
|
||||
{
|
||||
// Trick the compiler to think we have used self.timestamp
|
||||
// Workaround for "field is never used: `timestamp`" compiler nag.
|
||||
let _ = self.timestamp;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_module_path(&mut self, record: &Record) -> io::Result<()> {
|
||||
if !self.module_path {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(module_path) = record.module_path() {
|
||||
self.write_header_value(module_path)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_target(&mut self, record: &Record) -> io::Result<()> {
|
||||
if !self.target {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match record.target() {
|
||||
"" => Ok(()),
|
||||
target => self.write_header_value(target),
|
||||
}
|
||||
}
|
||||
|
||||
fn finish_header(&mut self) -> io::Result<()> {
|
||||
if self.written_header_value {
|
||||
let close_brace = self.subtle_style("]");
|
||||
write!(self.buf, "{} ", close_brace)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_args(&mut self, record: &Record) -> io::Result<()> {
|
||||
match self.indent {
|
||||
// Fast path for no indentation
|
||||
None => write!(self.buf, "{}{}", record.args(), self.suffix),
|
||||
|
||||
Some(indent_count) => {
|
||||
// Create a wrapper around the buffer only if we have to actually indent the message
|
||||
|
||||
struct IndentWrapper<'a, 'b: 'a> {
|
||||
fmt: &'a mut DefaultFormat<'b>,
|
||||
indent_count: usize,
|
||||
}
|
||||
|
||||
impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
let mut first = true;
|
||||
for chunk in buf.split(|&x| x == b'\n') {
|
||||
if !first {
|
||||
write!(
|
||||
self.fmt.buf,
|
||||
"{}{:width$}",
|
||||
self.fmt.suffix,
|
||||
"",
|
||||
width = self.indent_count
|
||||
)?;
|
||||
}
|
||||
self.fmt.buf.write_all(chunk)?;
|
||||
first = false;
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.fmt.buf.flush()
|
||||
}
|
||||
}
|
||||
|
||||
// The explicit scope here is just to make older versions of Rust happy
|
||||
{
|
||||
let mut wrapper = IndentWrapper {
|
||||
fmt: self,
|
||||
indent_count,
|
||||
};
|
||||
write!(wrapper, "{}", record.args())?;
|
||||
}
|
||||
|
||||
write!(self.buf, "{}", self.suffix)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use log::{Level, Record};
|
||||
|
||||
fn write_record(record: Record, fmt: DefaultFormat) -> String {
|
||||
let buf = fmt.buf.buf.clone();
|
||||
|
||||
fmt.write(&record).expect("failed to write record");
|
||||
|
||||
let buf = buf.borrow();
|
||||
String::from_utf8(buf.as_bytes().to_vec()).expect("failed to read record")
|
||||
}
|
||||
|
||||
fn write_target(target: &str, fmt: DefaultFormat) -> String {
|
||||
write_record(
|
||||
Record::builder()
|
||||
.args(format_args!("log\nmessage"))
|
||||
.level(Level::Info)
|
||||
.file(Some("test.rs"))
|
||||
.line(Some(144))
|
||||
.module_path(Some("test::path"))
|
||||
.target(target)
|
||||
.build(),
|
||||
fmt,
|
||||
)
|
||||
}
|
||||
|
||||
fn write(fmt: DefaultFormat) -> String {
|
||||
write_target("", fmt)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_with_header() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: true,
|
||||
target: false,
|
||||
level: true,
|
||||
written_header_value: false,
|
||||
indent: None,
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("[INFO test::path] log\nmessage\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_no_header() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: false,
|
||||
target: false,
|
||||
level: false,
|
||||
written_header_value: false,
|
||||
indent: None,
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("log\nmessage\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_indent_spaces() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: true,
|
||||
target: false,
|
||||
level: true,
|
||||
written_header_value: false,
|
||||
indent: Some(4),
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("[INFO test::path] log\n message\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_indent_zero_spaces() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: true,
|
||||
target: false,
|
||||
level: true,
|
||||
written_header_value: false,
|
||||
indent: Some(0),
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("[INFO test::path] log\nmessage\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_indent_spaces_no_header() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: false,
|
||||
target: false,
|
||||
level: false,
|
||||
written_header_value: false,
|
||||
indent: Some(4),
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("log\n message\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_suffix() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: false,
|
||||
target: false,
|
||||
level: false,
|
||||
written_header_value: false,
|
||||
indent: None,
|
||||
suffix: "\n\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("log\nmessage\n\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_suffix_with_indent() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: false,
|
||||
target: false,
|
||||
level: false,
|
||||
written_header_value: false,
|
||||
indent: Some(4),
|
||||
suffix: "\n\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("log\n\n message\n\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_target() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write_target(
|
||||
"target",
|
||||
DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: true,
|
||||
target: true,
|
||||
level: true,
|
||||
written_header_value: false,
|
||||
indent: None,
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!("[INFO test::path target] log\nmessage\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_empty_target() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write(DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: true,
|
||||
target: true,
|
||||
level: true,
|
||||
written_header_value: false,
|
||||
indent: None,
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
});
|
||||
|
||||
assert_eq!("[INFO test::path] log\nmessage\n", written);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_no_target() {
|
||||
let writer = writer::Builder::new()
|
||||
.write_style(WriteStyle::Never)
|
||||
.build();
|
||||
|
||||
let mut f = Formatter::new(&writer);
|
||||
|
||||
let written = write_target(
|
||||
"target",
|
||||
DefaultFormat {
|
||||
timestamp: None,
|
||||
module_path: true,
|
||||
target: false,
|
||||
level: true,
|
||||
written_header_value: false,
|
||||
indent: None,
|
||||
suffix: "\n",
|
||||
buf: &mut f,
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!("[INFO test::path] log\nmessage\n", written);
|
||||
}
|
||||
}
|
||||
351
third-party/vendor/env_logger/src/fmt/style.rs
vendored
Normal file
351
third-party/vendor/env_logger/src/fmt/style.rs
vendored
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::Buffer;
|
||||
|
||||
/// A set of styles to apply to the terminal output.
|
||||
///
|
||||
/// Call [`Formatter::style`] to get a `Style` and use the builder methods to
|
||||
/// set styling properties, like [color] and [weight].
|
||||
/// To print a value using the style, wrap it in a call to [`value`] when the log
|
||||
/// record is formatted.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a bold, red colored style and use it to print the log level:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
/// use env_logger::fmt::Color;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut level_style = buf.style();
|
||||
///
|
||||
/// level_style.set_color(Color::Red).set_bold(true);
|
||||
///
|
||||
/// writeln!(buf, "{}: {}",
|
||||
/// level_style.value(record.level()),
|
||||
/// record.args())
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Styles can be re-used to output multiple values:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
/// use env_logger::fmt::Color;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut bold = buf.style();
|
||||
///
|
||||
/// bold.set_bold(true);
|
||||
///
|
||||
/// writeln!(buf, "{}: {} {}",
|
||||
/// bold.value(record.level()),
|
||||
/// bold.value("some bold text"),
|
||||
/// record.args())
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// [`Formatter::style`]: struct.Formatter.html#method.style
|
||||
/// [color]: #method.set_color
|
||||
/// [weight]: #method.set_bold
|
||||
/// [`value`]: #method.value
|
||||
#[derive(Clone)]
|
||||
pub struct Style {
|
||||
pub(in crate::fmt) buf: Rc<RefCell<Buffer>>,
|
||||
pub(in crate::fmt) spec: termcolor::ColorSpec,
|
||||
}
|
||||
|
||||
impl Style {
|
||||
/// Set the text color.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a style with red text:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
/// use env_logger::fmt::Color;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut style = buf.style();
|
||||
///
|
||||
/// style.set_color(Color::Red);
|
||||
///
|
||||
/// writeln!(buf, "{}", style.value(record.args()))
|
||||
/// });
|
||||
/// ```
|
||||
pub fn set_color(&mut self, color: Color) -> &mut Style {
|
||||
self.spec.set_fg(Some(color.into_termcolor()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the text weight.
|
||||
///
|
||||
/// If `yes` is true then text will be written in bold.
|
||||
/// If `yes` is false then text will be written in the default weight.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a style with bold text:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut style = buf.style();
|
||||
///
|
||||
/// style.set_bold(true);
|
||||
///
|
||||
/// writeln!(buf, "{}", style.value(record.args()))
|
||||
/// });
|
||||
/// ```
|
||||
pub fn set_bold(&mut self, yes: bool) -> &mut Style {
|
||||
self.spec.set_bold(yes);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the text intensity.
|
||||
///
|
||||
/// If `yes` is true then text will be written in a brighter color.
|
||||
/// If `yes` is false then text will be written in the default color.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a style with intense text:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut style = buf.style();
|
||||
///
|
||||
/// style.set_intense(true);
|
||||
///
|
||||
/// writeln!(buf, "{}", style.value(record.args()))
|
||||
/// });
|
||||
/// ```
|
||||
pub fn set_intense(&mut self, yes: bool) -> &mut Style {
|
||||
self.spec.set_intense(yes);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether the text is dimmed.
|
||||
///
|
||||
/// If `yes` is true then text will be written in a dimmer color.
|
||||
/// If `yes` is false then text will be written in the default color.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a style with dimmed text:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut style = buf.style();
|
||||
///
|
||||
/// style.set_dimmed(true);
|
||||
///
|
||||
/// writeln!(buf, "{}", style.value(record.args()))
|
||||
/// });
|
||||
/// ```
|
||||
pub fn set_dimmed(&mut self, yes: bool) -> &mut Style {
|
||||
self.spec.set_dimmed(yes);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the background color.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a style with a yellow background:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
/// use env_logger::fmt::Color;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut style = buf.style();
|
||||
///
|
||||
/// style.set_bg(Color::Yellow);
|
||||
///
|
||||
/// writeln!(buf, "{}", style.value(record.args()))
|
||||
/// });
|
||||
/// ```
|
||||
pub fn set_bg(&mut self, color: Color) -> &mut Style {
|
||||
self.spec.set_bg(Some(color.into_termcolor()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Wrap a value in the style.
|
||||
///
|
||||
/// The same `Style` can be used to print multiple different values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a bold, red colored style and use it to print the log level:
|
||||
///
|
||||
/// ```
|
||||
/// use std::io::Write;
|
||||
/// use env_logger::fmt::Color;
|
||||
///
|
||||
/// let mut builder = env_logger::Builder::new();
|
||||
///
|
||||
/// builder.format(|buf, record| {
|
||||
/// let mut style = buf.style();
|
||||
///
|
||||
/// style.set_color(Color::Red).set_bold(true);
|
||||
///
|
||||
/// writeln!(buf, "{}: {}",
|
||||
/// style.value(record.level()),
|
||||
/// record.args())
|
||||
/// });
|
||||
/// ```
|
||||
pub fn value<T>(&self, value: T) -> StyledValue<T> {
|
||||
StyledValue {
|
||||
style: Cow::Borrowed(self),
|
||||
value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrap a value in the style by taking ownership of it.
|
||||
pub(crate) fn into_value<T>(self, value: T) -> StyledValue<'static, T> {
|
||||
StyledValue {
|
||||
style: Cow::Owned(self),
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Style {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Style").field("spec", &self.spec).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A value that can be printed using the given styles.
|
||||
///
|
||||
/// It is the result of calling [`Style::value`].
|
||||
///
|
||||
/// [`Style::value`]: struct.Style.html#method.value
|
||||
pub struct StyledValue<'a, T> {
|
||||
style: Cow<'a, Style>,
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<'a, T> StyledValue<'a, T> {
|
||||
fn write_fmt<F>(&self, f: F) -> fmt::Result
|
||||
where
|
||||
F: FnOnce() -> fmt::Result,
|
||||
{
|
||||
self.style
|
||||
.buf
|
||||
.borrow_mut()
|
||||
.set_color(&self.style.spec)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
|
||||
// Always try to reset the terminal style, even if writing failed
|
||||
let write = f();
|
||||
let reset = self.style.buf.borrow_mut().reset().map_err(|_| fmt::Error);
|
||||
|
||||
write.and(reset)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_styled_value_fmt {
|
||||
($($fmt_trait:path),*) => {
|
||||
$(
|
||||
impl<'a, T: $fmt_trait> $fmt_trait for StyledValue<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter)->fmt::Result {
|
||||
self.write_fmt(|| T::fmt(&self.value, f))
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_styled_value_fmt!(
|
||||
fmt::Debug,
|
||||
fmt::Display,
|
||||
fmt::Pointer,
|
||||
fmt::Octal,
|
||||
fmt::Binary,
|
||||
fmt::UpperHex,
|
||||
fmt::LowerHex,
|
||||
fmt::UpperExp,
|
||||
fmt::LowerExp
|
||||
);
|
||||
|
||||
// The `Color` type is copied from https://github.com/BurntSushi/termcolor
|
||||
|
||||
/// The set of available colors for the terminal foreground/background.
|
||||
///
|
||||
/// The `Ansi256` and `Rgb` colors will only output the correct codes when
|
||||
/// paired with the `Ansi` `WriteColor` implementation.
|
||||
///
|
||||
/// The `Ansi256` and `Rgb` color types are not supported when writing colors
|
||||
/// on Windows using the console. If they are used on Windows, then they are
|
||||
/// silently ignored and no colors will be emitted.
|
||||
///
|
||||
/// This set may expand over time.
|
||||
///
|
||||
/// This type has a `FromStr` impl that can parse colors from their human
|
||||
/// readable form. The format is as follows:
|
||||
///
|
||||
/// 1. Any of the explicitly listed colors in English. They are matched
|
||||
/// case insensitively.
|
||||
/// 2. A single 8-bit integer, in either decimal or hexadecimal format.
|
||||
/// 3. A triple of 8-bit integers separated by a comma, where each integer is
|
||||
/// in decimal or hexadecimal format.
|
||||
///
|
||||
/// Hexadecimal numbers are written with a `0x` prefix.
|
||||
#[allow(missing_docs)]
|
||||
#[non_exhaustive]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Color {
|
||||
Black,
|
||||
Blue,
|
||||
Green,
|
||||
Red,
|
||||
Cyan,
|
||||
Magenta,
|
||||
Yellow,
|
||||
White,
|
||||
Ansi256(u8),
|
||||
Rgb(u8, u8, u8),
|
||||
}
|
||||
|
||||
impl Color {
|
||||
fn into_termcolor(self) -> termcolor::Color {
|
||||
match self {
|
||||
Color::Black => termcolor::Color::Black,
|
||||
Color::Blue => termcolor::Color::Blue,
|
||||
Color::Green => termcolor::Color::Green,
|
||||
Color::Red => termcolor::Color::Red,
|
||||
Color::Cyan => termcolor::Color::Cyan,
|
||||
Color::Magenta => termcolor::Color::Magenta,
|
||||
Color::Yellow => termcolor::Color::Yellow,
|
||||
Color::White => termcolor::Color::White,
|
||||
Color::Ansi256(value) => termcolor::Color::Ansi256(value),
|
||||
Color::Rgb(r, g, b) => termcolor::Color::Rgb(r, g, b),
|
||||
}
|
||||
}
|
||||
}
|
||||
33
third-party/vendor/env_logger/src/fmt/writer/atty.rs
vendored
Normal file
33
third-party/vendor/env_logger/src/fmt/writer/atty.rs
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
This internal module contains the terminal detection implementation.
|
||||
|
||||
If the `auto-color` feature is enabled then we detect whether we're attached to a particular TTY.
|
||||
Otherwise, assume we're not attached to anything. This effectively prevents styles from being
|
||||
printed.
|
||||
*/
|
||||
|
||||
#[cfg(feature = "auto-color")]
|
||||
mod imp {
|
||||
use is_terminal::IsTerminal;
|
||||
|
||||
pub(in crate::fmt) fn is_stdout() -> bool {
|
||||
std::io::stdout().is_terminal()
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn is_stderr() -> bool {
|
||||
std::io::stderr().is_terminal()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "auto-color"))]
|
||||
mod imp {
|
||||
pub(in crate::fmt) fn is_stdout() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn is_stderr() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt) use self::imp::*;
|
||||
15
third-party/vendor/env_logger/src/fmt/writer/buffer/mod.rs
vendored
Normal file
15
third-party/vendor/env_logger/src/fmt/writer/buffer/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
This internal module contains the style and terminal writing implementation.
|
||||
|
||||
Its public API is available when the `termcolor` crate is available.
|
||||
The terminal printing is shimmed when the `termcolor` crate is not available.
|
||||
*/
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
mod termcolor;
|
||||
#[cfg(feature = "color")]
|
||||
pub(in crate::fmt) use self::termcolor::*;
|
||||
#[cfg(not(feature = "color"))]
|
||||
mod plain;
|
||||
#[cfg(not(feature = "color"))]
|
||||
pub(in crate::fmt) use plain::*;
|
||||
68
third-party/vendor/env_logger/src/fmt/writer/buffer/plain.rs
vendored
Normal file
68
third-party/vendor/env_logger/src/fmt/writer/buffer/plain.rs
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
use std::{io, sync::Mutex};
|
||||
|
||||
use crate::fmt::{WritableTarget, WriteStyle};
|
||||
|
||||
pub(in crate::fmt::writer) struct BufferWriter {
|
||||
target: WritableTarget,
|
||||
}
|
||||
|
||||
impl BufferWriter {
|
||||
pub(in crate::fmt::writer) fn stderr(is_test: bool, _write_style: WriteStyle) -> Self {
|
||||
BufferWriter {
|
||||
target: if is_test {
|
||||
WritableTarget::PrintStderr
|
||||
} else {
|
||||
WritableTarget::WriteStderr
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn stdout(is_test: bool, _write_style: WriteStyle) -> Self {
|
||||
BufferWriter {
|
||||
target: if is_test {
|
||||
WritableTarget::PrintStdout
|
||||
} else {
|
||||
WritableTarget::WriteStdout
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn pipe(pipe: Box<Mutex<dyn io::Write + Send + 'static>>) -> Self {
|
||||
BufferWriter {
|
||||
target: WritableTarget::Pipe(pipe),
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn write_style(&self) -> WriteStyle {
|
||||
WriteStyle::Never
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
|
||||
Buffer(Vec::new())
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
|
||||
self.target.print(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt) struct Buffer(Vec<u8>);
|
||||
|
||||
impl Buffer {
|
||||
pub(in crate::fmt) fn clear(&mut self) {
|
||||
self.0.clear();
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.extend(buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
108
third-party/vendor/env_logger/src/fmt/writer/buffer/termcolor.rs
vendored
Normal file
108
third-party/vendor/env_logger/src/fmt/writer/buffer/termcolor.rs
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
use std::io::{self, Write};
|
||||
use std::sync::Mutex;
|
||||
|
||||
use termcolor::{self, ColorSpec, WriteColor};
|
||||
|
||||
use crate::fmt::{WritableTarget, WriteStyle};
|
||||
|
||||
pub(in crate::fmt::writer) struct BufferWriter {
|
||||
inner: termcolor::BufferWriter,
|
||||
uncolored_target: Option<WritableTarget>,
|
||||
write_style: WriteStyle,
|
||||
}
|
||||
|
||||
impl BufferWriter {
|
||||
pub(in crate::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self {
|
||||
BufferWriter {
|
||||
inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
|
||||
uncolored_target: if is_test {
|
||||
Some(WritableTarget::PrintStderr)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
write_style,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self {
|
||||
BufferWriter {
|
||||
inner: termcolor::BufferWriter::stdout(write_style.into_color_choice()),
|
||||
uncolored_target: if is_test {
|
||||
Some(WritableTarget::PrintStdout)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
write_style,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn pipe(pipe: Box<Mutex<dyn io::Write + Send + 'static>>) -> Self {
|
||||
let write_style = WriteStyle::Never;
|
||||
BufferWriter {
|
||||
// The inner Buffer is never printed from, but it is still needed to handle coloring and other formatting
|
||||
inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
|
||||
uncolored_target: Some(WritableTarget::Pipe(pipe)),
|
||||
write_style,
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn write_style(&self) -> WriteStyle {
|
||||
self.write_style
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
|
||||
Buffer {
|
||||
inner: self.inner.buffer(),
|
||||
has_uncolored_target: self.uncolored_target.is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
|
||||
if let Some(target) = &self.uncolored_target {
|
||||
target.print(buf)
|
||||
} else {
|
||||
self.inner.print(&buf.inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt) struct Buffer {
|
||||
inner: termcolor::Buffer,
|
||||
has_uncolored_target: bool,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub(in crate::fmt) fn clear(&mut self) {
|
||||
self.inner.clear()
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.inner.write(buf)
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
|
||||
self.inner.flush()
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn as_bytes(&self) -> &[u8] {
|
||||
self.inner.as_slice()
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
|
||||
// Ignore styles for test captured logs because they can't be printed
|
||||
if !self.has_uncolored_target {
|
||||
self.inner.set_color(spec)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::fmt) fn reset(&mut self) -> io::Result<()> {
|
||||
// Ignore styles for test captured logs because they can't be printed
|
||||
if !self.has_uncolored_target {
|
||||
self.inner.reset()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
288
third-party/vendor/env_logger/src/fmt/writer/mod.rs
vendored
Normal file
288
third-party/vendor/env_logger/src/fmt/writer/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
mod atty;
|
||||
mod buffer;
|
||||
|
||||
use self::atty::{is_stderr, is_stdout};
|
||||
use self::buffer::BufferWriter;
|
||||
use std::{fmt, io, mem, sync::Mutex};
|
||||
|
||||
pub(super) mod glob {
|
||||
pub use super::*;
|
||||
}
|
||||
|
||||
pub(super) use self::buffer::Buffer;
|
||||
|
||||
/// Log target, either `stdout`, `stderr` or a custom pipe.
|
||||
#[non_exhaustive]
|
||||
pub enum Target {
|
||||
/// Logs will be sent to standard output.
|
||||
Stdout,
|
||||
/// Logs will be sent to standard error.
|
||||
Stderr,
|
||||
/// Logs will be sent to a custom pipe.
|
||||
Pipe(Box<dyn io::Write + Send + 'static>),
|
||||
}
|
||||
|
||||
impl Default for Target {
|
||||
fn default() -> Self {
|
||||
Target::Stderr
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Target {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Stdout => "stdout",
|
||||
Self::Stderr => "stderr",
|
||||
Self::Pipe(_) => "pipe",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Log target, either `stdout`, `stderr` or a custom pipe.
|
||||
///
|
||||
/// Same as `Target`, except the pipe is wrapped in a mutex for interior mutability.
|
||||
pub(super) enum WritableTarget {
|
||||
/// Logs will be written to standard output.
|
||||
#[allow(dead_code)]
|
||||
WriteStdout,
|
||||
/// Logs will be printed to standard output.
|
||||
PrintStdout,
|
||||
/// Logs will be written to standard error.
|
||||
#[allow(dead_code)]
|
||||
WriteStderr,
|
||||
/// Logs will be printed to standard error.
|
||||
PrintStderr,
|
||||
/// Logs will be sent to a custom pipe.
|
||||
Pipe(Box<Mutex<dyn io::Write + Send + 'static>>),
|
||||
}
|
||||
|
||||
impl WritableTarget {
|
||||
fn print(&self, buf: &Buffer) -> io::Result<()> {
|
||||
use std::io::Write as _;
|
||||
|
||||
let buf = buf.as_bytes();
|
||||
match self {
|
||||
WritableTarget::WriteStdout => {
|
||||
let stream = std::io::stdout();
|
||||
let mut stream = stream.lock();
|
||||
stream.write_all(buf)?;
|
||||
stream.flush()?;
|
||||
}
|
||||
WritableTarget::PrintStdout => print!("{}", String::from_utf8_lossy(buf)),
|
||||
WritableTarget::WriteStderr => {
|
||||
let stream = std::io::stderr();
|
||||
let mut stream = stream.lock();
|
||||
stream.write_all(buf)?;
|
||||
stream.flush()?;
|
||||
}
|
||||
WritableTarget::PrintStderr => eprint!("{}", String::from_utf8_lossy(buf)),
|
||||
// Safety: If the target type is `Pipe`, `target_pipe` will always be non-empty.
|
||||
WritableTarget::Pipe(pipe) => {
|
||||
let mut stream = pipe.lock().unwrap();
|
||||
stream.write_all(buf)?;
|
||||
stream.flush()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for WritableTarget {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::WriteStdout => "stdout",
|
||||
Self::PrintStdout => "stdout",
|
||||
Self::WriteStderr => "stderr",
|
||||
Self::PrintStderr => "stderr",
|
||||
Self::Pipe(_) => "pipe",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
/// Whether or not to print styles to the target.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum WriteStyle {
|
||||
/// Try to print styles, but don't force the issue.
|
||||
Auto,
|
||||
/// Try very hard to print styles.
|
||||
Always,
|
||||
/// Never print styles.
|
||||
Never,
|
||||
}
|
||||
|
||||
impl Default for WriteStyle {
|
||||
fn default() -> Self {
|
||||
WriteStyle::Auto
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
impl WriteStyle {
|
||||
fn into_color_choice(self) -> ::termcolor::ColorChoice {
|
||||
match self {
|
||||
WriteStyle::Always => ::termcolor::ColorChoice::Always,
|
||||
WriteStyle::Auto => ::termcolor::ColorChoice::Auto,
|
||||
WriteStyle::Never => ::termcolor::ColorChoice::Never,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A terminal target with color awareness.
|
||||
pub(crate) struct Writer {
|
||||
inner: BufferWriter,
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
pub fn write_style(&self) -> WriteStyle {
|
||||
self.inner.write_style()
|
||||
}
|
||||
|
||||
pub(super) fn buffer(&self) -> Buffer {
|
||||
self.inner.buffer()
|
||||
}
|
||||
|
||||
pub(super) fn print(&self, buf: &Buffer) -> io::Result<()> {
|
||||
self.inner.print(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Writer {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Writer").finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A builder for a terminal writer.
|
||||
///
|
||||
/// The target and style choice can be configured before building.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Builder {
|
||||
target: Target,
|
||||
write_style: WriteStyle,
|
||||
is_test: bool,
|
||||
built: bool,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Initialize the writer builder with defaults.
|
||||
pub(crate) fn new() -> Self {
|
||||
Builder {
|
||||
target: Default::default(),
|
||||
write_style: Default::default(),
|
||||
is_test: false,
|
||||
built: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the target to write to.
|
||||
pub(crate) fn target(&mut self, target: Target) -> &mut Self {
|
||||
self.target = target;
|
||||
self
|
||||
}
|
||||
|
||||
/// Parses a style choice string.
|
||||
///
|
||||
/// See the [Disabling colors] section for more details.
|
||||
///
|
||||
/// [Disabling colors]: ../index.html#disabling-colors
|
||||
pub(crate) fn parse_write_style(&mut self, write_style: &str) -> &mut Self {
|
||||
self.write_style(parse_write_style(write_style))
|
||||
}
|
||||
|
||||
/// Whether or not to print style characters when writing.
|
||||
pub(crate) fn write_style(&mut self, write_style: WriteStyle) -> &mut Self {
|
||||
self.write_style = write_style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Whether or not to capture logs for `cargo test`.
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
pub(crate) fn is_test(&mut self, is_test: bool) -> &mut Self {
|
||||
self.is_test = is_test;
|
||||
self
|
||||
}
|
||||
|
||||
/// Build a terminal writer.
|
||||
pub(crate) fn build(&mut self) -> Writer {
|
||||
assert!(!self.built, "attempt to re-use consumed builder");
|
||||
self.built = true;
|
||||
|
||||
let color_choice = match self.write_style {
|
||||
WriteStyle::Auto => {
|
||||
if match &self.target {
|
||||
Target::Stderr => is_stderr(),
|
||||
Target::Stdout => is_stdout(),
|
||||
Target::Pipe(_) => false,
|
||||
} {
|
||||
WriteStyle::Auto
|
||||
} else {
|
||||
WriteStyle::Never
|
||||
}
|
||||
}
|
||||
color_choice => color_choice,
|
||||
};
|
||||
let color_choice = if self.is_test {
|
||||
WriteStyle::Never
|
||||
} else {
|
||||
color_choice
|
||||
};
|
||||
|
||||
let writer = match mem::take(&mut self.target) {
|
||||
Target::Stderr => BufferWriter::stderr(self.is_test, color_choice),
|
||||
Target::Stdout => BufferWriter::stdout(self.is_test, color_choice),
|
||||
Target::Pipe(pipe) => BufferWriter::pipe(Box::new(Mutex::new(pipe))),
|
||||
};
|
||||
|
||||
Writer { inner: writer }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
fn default() -> Self {
|
||||
Builder::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_write_style(spec: &str) -> WriteStyle {
|
||||
match spec {
|
||||
"auto" => WriteStyle::Auto,
|
||||
"always" => WriteStyle::Always,
|
||||
"never" => WriteStyle::Never,
|
||||
_ => Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_write_style_valid() {
|
||||
let inputs = vec![
|
||||
("auto", WriteStyle::Auto),
|
||||
("always", WriteStyle::Always),
|
||||
("never", WriteStyle::Never),
|
||||
];
|
||||
|
||||
for (input, expected) in inputs {
|
||||
assert_eq!(expected, parse_write_style(input));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_write_style_invalid() {
|
||||
let inputs = vec!["", "true", "false", "NEVER!!"];
|
||||
|
||||
for input in inputs {
|
||||
assert_eq!(WriteStyle::Auto, parse_write_style(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
284
third-party/vendor/env_logger/src/lib.rs
vendored
Normal file
284
third-party/vendor/env_logger/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A simple logger that can be configured via environment variables, for use
|
||||
//! with the logging facade exposed by the [`log` crate][log-crate-url].
|
||||
//!
|
||||
//! Despite having "env" in its name, **`env_logger`** can also be configured by
|
||||
//! other means besides environment variables. See [the examples][gh-repo-examples]
|
||||
//! in the source repository for more approaches.
|
||||
//!
|
||||
//! By default, `env_logger` writes logs to `stderr`, but can be configured to
|
||||
//! instead write them to `stdout`.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```
|
||||
//! use log::{debug, error, log_enabled, info, Level};
|
||||
//!
|
||||
//! env_logger::init();
|
||||
//!
|
||||
//! debug!("this is a debug {}", "message");
|
||||
//! error!("this is printed by default");
|
||||
//!
|
||||
//! if log_enabled!(Level::Info) {
|
||||
//! let x = 3 * 4; // expensive computation
|
||||
//! info!("the answer was: {}", x);
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Assumes the binary is `main`:
|
||||
//!
|
||||
//! ```{.bash}
|
||||
//! $ RUST_LOG=error ./main
|
||||
//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
|
||||
//! ```
|
||||
//!
|
||||
//! ```{.bash}
|
||||
//! $ RUST_LOG=info ./main
|
||||
//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
|
||||
//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
|
||||
//! ```
|
||||
//!
|
||||
//! ```{.bash}
|
||||
//! $ RUST_LOG=debug ./main
|
||||
//! [2017-11-09T02:12:24Z DEBUG main] this is a debug message
|
||||
//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
|
||||
//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
|
||||
//! ```
|
||||
//!
|
||||
//! You can also set the log level on a per module basis:
|
||||
//!
|
||||
//! ```{.bash}
|
||||
//! $ RUST_LOG=main=info ./main
|
||||
//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
|
||||
//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
|
||||
//! ```
|
||||
//!
|
||||
//! And enable all logging:
|
||||
//!
|
||||
//! ```{.bash}
|
||||
//! $ RUST_LOG=main ./main
|
||||
//! [2017-11-09T02:12:24Z DEBUG main] this is a debug message
|
||||
//! [2017-11-09T02:12:24Z ERROR main] this is printed by default
|
||||
//! [2017-11-09T02:12:24Z INFO main] the answer was: 12
|
||||
//! ```
|
||||
//!
|
||||
//! If the binary name contains hyphens, you will need to replace
|
||||
//! them with underscores:
|
||||
//!
|
||||
//! ```{.bash}
|
||||
//! $ RUST_LOG=my_app ./my-app
|
||||
//! [2017-11-09T02:12:24Z DEBUG my_app] this is a debug message
|
||||
//! [2017-11-09T02:12:24Z ERROR my_app] this is printed by default
|
||||
//! [2017-11-09T02:12:24Z INFO my_app] the answer was: 12
|
||||
//! ```
|
||||
//!
|
||||
//! This is because Rust modules and crates cannot contain hyphens
|
||||
//! in their name, although `cargo` continues to accept them.
|
||||
//!
|
||||
//! See the documentation for the [`log` crate][log-crate-url] for more
|
||||
//! information about its API.
|
||||
//!
|
||||
//! ## Enabling logging
|
||||
//!
|
||||
//! **By default all logging is disabled except for the `error` level**
|
||||
//!
|
||||
//! The **`RUST_LOG`** environment variable controls logging with the syntax:
|
||||
//! ```text
|
||||
//! RUST_LOG=[target][=][level][,...]
|
||||
//! ```
|
||||
//! Or in other words, its a comma-separated list of directives.
|
||||
//! Directives can filter by **target**, by **level**, or both (using `=`).
|
||||
//!
|
||||
//! For example,
|
||||
//! ```text
|
||||
//! RUST_LOG=data=debug,hardware=debug
|
||||
//! ```
|
||||
//!
|
||||
//! **target** is typically the path of the module the message
|
||||
//! in question originated from, though it can be overridden.
|
||||
//! The path is rooted in the name of the crate it was compiled for, so if
|
||||
//! your program is in a file called, for example, `hello.rs`, the path would
|
||||
//! simply be `hello`.
|
||||
//!
|
||||
//! Furthermore, the log can be filtered using prefix-search based on the
|
||||
//! specified log target.
|
||||
//!
|
||||
//! For example, `RUST_LOG=example` would match the following targets:
|
||||
//! - `example`
|
||||
//! - `example::test`
|
||||
//! - `example::test::module::submodule`
|
||||
//! - `examples::and_more_examples`
|
||||
//!
|
||||
//! When providing the crate name or a module path, explicitly specifying the
|
||||
//! log level is optional. If omitted, all logging for the item will be
|
||||
//! enabled.
|
||||
//!
|
||||
//! **level** is the maximum [`log::Level`][level-enum] to be shown and includes:
|
||||
//! - `error`
|
||||
//! - `warn`
|
||||
//! - `info`
|
||||
//! - `debug`
|
||||
//! - `trace`
|
||||
//! - `off` (pseudo level to disable all logging for the target)
|
||||
//!
|
||||
//! Logging level names are case-insensitive; e.g.,
|
||||
//! `debug`, `DEBUG`, and `dEbuG` all represent the same logging level. For
|
||||
//! consistency, our convention is to use the lower case names. Where our docs
|
||||
//! do use other forms, they do so in the context of specific examples, so you
|
||||
//! won't be surprised if you see similar usage in the wild.
|
||||
//!
|
||||
//! Some examples of valid values of `RUST_LOG` are:
|
||||
//!
|
||||
//! - `RUST_LOG=hello` turns on all logging for the `hello` module
|
||||
//! - `RUST_LOG=trace` turns on all logging for the application, regardless of its name
|
||||
//! - `RUST_LOG=TRACE` turns on all logging for the application, regardless of its name (same as previous)
|
||||
//! - `RUST_LOG=info` turns on all info logging
|
||||
//! - `RUST_LOG=INFO` turns on all info logging (same as previous)
|
||||
//! - `RUST_LOG=hello=debug` turns on debug logging for `hello`
|
||||
//! - `RUST_LOG=hello=DEBUG` turns on debug logging for `hello` (same as previous)
|
||||
//! - `RUST_LOG=hello,std::option` turns on `hello`, and std's option logging
|
||||
//! - `RUST_LOG=error,hello=warn` turn on global error logging and also warn for `hello`
|
||||
//! - `RUST_LOG=error,hello=off` turn on global error logging, but turn off logging for `hello`
|
||||
//! - `RUST_LOG=off` turns off all logging for the application
|
||||
//! - `RUST_LOG=OFF` turns off all logging for the application (same as previous)
|
||||
//!
|
||||
//! ## Filtering results
|
||||
//!
|
||||
//! A `RUST_LOG` directive may include a regex filter. The syntax is to append `/`
|
||||
//! followed by a regex. Each message is checked against the regex, and is only
|
||||
//! logged if it matches. Note that the matching is done after formatting the
|
||||
//! log string but before adding any logging meta-data. There is a single filter
|
||||
//! for all modules.
|
||||
//!
|
||||
//! Some examples:
|
||||
//!
|
||||
//! * `hello/foo` turns on all logging for the 'hello' module where the log
|
||||
//! message includes 'foo'.
|
||||
//! * `info/f.o` turns on all info logging where the log message includes 'foo',
|
||||
//! 'f1o', 'fao', etc.
|
||||
//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log
|
||||
//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc.
|
||||
//! * `error,hello=warn/[0-9]scopes` turn on global error logging and also
|
||||
//! warn for hello. In both cases the log message must include a single digit
|
||||
//! number followed by 'scopes'.
|
||||
//!
|
||||
//! ## Capturing logs in tests
|
||||
//!
|
||||
//! Records logged during `cargo test` will not be captured by the test harness by default.
|
||||
//! The [`Builder::is_test`] method can be used in unit tests to ensure logs will be captured:
|
||||
//!
|
||||
//! ```
|
||||
//! #[cfg(test)]
|
||||
//! mod tests {
|
||||
//! use log::info;
|
||||
//!
|
||||
//! fn init() {
|
||||
//! let _ = env_logger::builder().is_test(true).try_init();
|
||||
//! }
|
||||
//!
|
||||
//! #[test]
|
||||
//! fn it_works() {
|
||||
//! init();
|
||||
//!
|
||||
//! info!("This record will be captured by `cargo test`");
|
||||
//!
|
||||
//! assert_eq!(2, 1 + 1);
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Enabling test capturing comes at the expense of color and other style support
|
||||
//! and may have performance implications.
|
||||
//!
|
||||
//! ## Disabling colors
|
||||
//!
|
||||
//! Colors and other styles can be configured with the `RUST_LOG_STYLE`
|
||||
//! environment variable. It accepts the following values:
|
||||
//!
|
||||
//! * `auto` (default) will attempt to print style characters, but don't force the issue.
|
||||
//! If the console isn't available on Windows, or if TERM=dumb, for example, then don't print colors.
|
||||
//! * `always` will always print style characters even if they aren't supported by the terminal.
|
||||
//! This includes emitting ANSI colors on Windows if the console API is unavailable.
|
||||
//! * `never` will never print style characters.
|
||||
//!
|
||||
//! ## Tweaking the default format
|
||||
//!
|
||||
//! Parts of the default format can be excluded from the log output using the [`Builder`].
|
||||
//! The following example excludes the timestamp from the log output:
|
||||
//!
|
||||
//! ```
|
||||
//! env_logger::builder()
|
||||
//! .format_timestamp(None)
|
||||
//! .init();
|
||||
//! ```
|
||||
//!
|
||||
//! ### Stability of the default format
|
||||
//!
|
||||
//! The default format won't optimise for long-term stability, and explicitly makes no
|
||||
//! guarantees about the stability of its output across major, minor or patch version
|
||||
//! bumps during `0.x`.
|
||||
//!
|
||||
//! If you want to capture or interpret the output of `env_logger` programmatically
|
||||
//! then you should use a custom format.
|
||||
//!
|
||||
//! ### Using a custom format
|
||||
//!
|
||||
//! Custom formats can be provided as closures to the [`Builder`].
|
||||
//! These closures take a [`Formatter`][crate::fmt::Formatter] and `log::Record` as arguments:
|
||||
//!
|
||||
//! ```
|
||||
//! use std::io::Write;
|
||||
//!
|
||||
//! env_logger::builder()
|
||||
//! .format(|buf, record| {
|
||||
//! writeln!(buf, "{}: {}", record.level(), record.args())
|
||||
//! })
|
||||
//! .init();
|
||||
//! ```
|
||||
//!
|
||||
//! See the [`fmt`] module for more details about custom formats.
|
||||
//!
|
||||
//! ## Specifying defaults for environment variables
|
||||
//!
|
||||
//! `env_logger` can read configuration from environment variables.
|
||||
//! If these variables aren't present, the default value to use can be tweaked with the [`Env`] type.
|
||||
//! The following example defaults to log `warn` and above if the `RUST_LOG` environment variable
|
||||
//! isn't set:
|
||||
//!
|
||||
//! ```
|
||||
//! use env_logger::Env;
|
||||
//!
|
||||
//! env_logger::Builder::from_env(Env::default().default_filter_or("warn")).init();
|
||||
//! ```
|
||||
//!
|
||||
//! [gh-repo-examples]: https://github.com/rust-cli/env_logger/tree/main/examples
|
||||
//! [level-enum]: https://docs.rs/log/latest/log/enum.Level.html
|
||||
//! [log-crate-url]: https://docs.rs/log
|
||||
//! [`Builder`]: struct.Builder.html
|
||||
//! [`Builder::is_test`]: struct.Builder.html#method.is_test
|
||||
//! [`Env`]: struct.Env.html
|
||||
//! [`fmt`]: fmt/index.html
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://www.rust-lang.org/static/images/favicon.ico"
|
||||
)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
// When compiled for the rustc compiler itself we want to make sure that this is
|
||||
// an unstable crate
|
||||
#![cfg_attr(rustbuild, feature(staged_api, rustc_private))]
|
||||
#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))]
|
||||
#![deny(missing_debug_implementations, missing_docs)]
|
||||
|
||||
mod logger;
|
||||
|
||||
pub mod filter;
|
||||
pub mod fmt;
|
||||
|
||||
pub use self::fmt::glob::*;
|
||||
pub use self::logger::*;
|
||||
1016
third-party/vendor/env_logger/src/logger.rs
vendored
Normal file
1016
third-party/vendor/env_logger/src/logger.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
40
third-party/vendor/env_logger/tests/init-twice-retains-filter.rs
vendored
Normal file
40
third-party/vendor/env_logger/tests/init-twice-retains-filter.rs
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
extern crate env_logger;
|
||||
extern crate log;
|
||||
|
||||
use std::env;
|
||||
use std::process;
|
||||
use std::str;
|
||||
|
||||
fn main() {
|
||||
if env::var("YOU_ARE_TESTING_NOW").is_ok() {
|
||||
// Init from the env (which should set the max level to `Debug`)
|
||||
env_logger::init();
|
||||
|
||||
assert_eq!(log::LevelFilter::Debug, log::max_level());
|
||||
|
||||
// Init again using a different max level
|
||||
// This shouldn't clobber the level that was previously set
|
||||
env_logger::Builder::new()
|
||||
.parse_filters("info")
|
||||
.try_init()
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(log::LevelFilter::Debug, log::max_level());
|
||||
return;
|
||||
}
|
||||
|
||||
let exe = env::current_exe().unwrap();
|
||||
let out = process::Command::new(exe)
|
||||
.env("YOU_ARE_TESTING_NOW", "1")
|
||||
.env("RUST_LOG", "debug")
|
||||
.output()
|
||||
.unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
|
||||
if out.status.success() {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("test failed: {}", out.status);
|
||||
println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap());
|
||||
println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap());
|
||||
process::exit(1);
|
||||
}
|
||||
39
third-party/vendor/env_logger/tests/log-in-log.rs
vendored
Normal file
39
third-party/vendor/env_logger/tests/log-in-log.rs
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate env_logger;
|
||||
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::process;
|
||||
use std::str;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl fmt::Display for Foo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
info!("test");
|
||||
f.write_str("bar")
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
if env::var("YOU_ARE_TESTING_NOW").is_ok() {
|
||||
return info!("{}", Foo);
|
||||
}
|
||||
|
||||
let exe = env::current_exe().unwrap();
|
||||
let out = process::Command::new(exe)
|
||||
.env("YOU_ARE_TESTING_NOW", "1")
|
||||
.env("RUST_LOG", "debug")
|
||||
.output()
|
||||
.unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
|
||||
if out.status.success() {
|
||||
return;
|
||||
}
|
||||
|
||||
println!("test failed: {}", out.status);
|
||||
println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap());
|
||||
println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap());
|
||||
process::exit(1);
|
||||
}
|
||||
66
third-party/vendor/env_logger/tests/log_tls_dtors.rs
vendored
Normal file
66
third-party/vendor/env_logger/tests/log_tls_dtors.rs
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate env_logger;
|
||||
|
||||
use std::env;
|
||||
use std::process;
|
||||
use std::str;
|
||||
use std::thread;
|
||||
|
||||
struct DropMe;
|
||||
|
||||
impl Drop for DropMe {
|
||||
fn drop(&mut self) {
|
||||
debug!("Dropping now");
|
||||
}
|
||||
}
|
||||
|
||||
fn run() {
|
||||
// Use multiple thread local values to increase the chance that our TLS
|
||||
// value will get destroyed after the FORMATTER key in the library
|
||||
thread_local! {
|
||||
static DROP_ME_0: DropMe = DropMe;
|
||||
static DROP_ME_1: DropMe = DropMe;
|
||||
static DROP_ME_2: DropMe = DropMe;
|
||||
static DROP_ME_3: DropMe = DropMe;
|
||||
static DROP_ME_4: DropMe = DropMe;
|
||||
static DROP_ME_5: DropMe = DropMe;
|
||||
static DROP_ME_6: DropMe = DropMe;
|
||||
static DROP_ME_7: DropMe = DropMe;
|
||||
static DROP_ME_8: DropMe = DropMe;
|
||||
static DROP_ME_9: DropMe = DropMe;
|
||||
}
|
||||
DROP_ME_0.with(|_| {});
|
||||
DROP_ME_1.with(|_| {});
|
||||
DROP_ME_2.with(|_| {});
|
||||
DROP_ME_3.with(|_| {});
|
||||
DROP_ME_4.with(|_| {});
|
||||
DROP_ME_5.with(|_| {});
|
||||
DROP_ME_6.with(|_| {});
|
||||
DROP_ME_7.with(|_| {});
|
||||
DROP_ME_8.with(|_| {});
|
||||
DROP_ME_9.with(|_| {});
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
if env::var("YOU_ARE_TESTING_NOW").is_ok() {
|
||||
// Run on a separate thread because TLS values on the main thread
|
||||
// won't have their destructors run if pthread is used.
|
||||
// https://doc.rust-lang.org/std/thread/struct.LocalKey.html#platform-specific-behavior
|
||||
thread::spawn(run).join().unwrap();
|
||||
} else {
|
||||
let exe = env::current_exe().unwrap();
|
||||
let out = process::Command::new(exe)
|
||||
.env("YOU_ARE_TESTING_NOW", "1")
|
||||
.env("RUST_LOG", "debug")
|
||||
.output()
|
||||
.unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
|
||||
if !out.status.success() {
|
||||
println!("test failed: {}", out.status);
|
||||
println!("--- stdout\n{}", str::from_utf8(&out.stdout).unwrap());
|
||||
println!("--- stderr\n{}", str::from_utf8(&out.stderr).unwrap());
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
third-party/vendor/env_logger/tests/regexp_filter.rs
vendored
Normal file
57
third-party/vendor/env_logger/tests/regexp_filter.rs
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#[macro_use]
|
||||
extern crate log;
|
||||
extern crate env_logger;
|
||||
|
||||
use std::env;
|
||||
use std::process;
|
||||
use std::str;
|
||||
|
||||
fn main() {
|
||||
if env::var("LOG_REGEXP_TEST").ok() == Some(String::from("1")) {
|
||||
child_main();
|
||||
} else {
|
||||
parent_main()
|
||||
}
|
||||
}
|
||||
|
||||
fn child_main() {
|
||||
env_logger::init();
|
||||
info!("XYZ Message");
|
||||
}
|
||||
|
||||
fn run_child(rust_log: String) -> bool {
|
||||
let exe = env::current_exe().unwrap();
|
||||
let out = process::Command::new(exe)
|
||||
.env("LOG_REGEXP_TEST", "1")
|
||||
.env("RUST_LOG", rust_log)
|
||||
.output()
|
||||
.unwrap_or_else(|e| panic!("Unable to start child process: {}", e));
|
||||
str::from_utf8(out.stderr.as_ref())
|
||||
.unwrap()
|
||||
.contains("XYZ Message")
|
||||
}
|
||||
|
||||
fn assert_message_printed(rust_log: &str) {
|
||||
if !run_child(rust_log.to_string()) {
|
||||
panic!("RUST_LOG={} should allow the test log message", rust_log)
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_message_not_printed(rust_log: &str) {
|
||||
if run_child(rust_log.to_string()) {
|
||||
panic!(
|
||||
"RUST_LOG={} should not allow the test log message",
|
||||
rust_log
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_main() {
|
||||
// test normal log severity levels
|
||||
assert_message_printed("info");
|
||||
assert_message_not_printed("warn");
|
||||
|
||||
// test of regular expression filters
|
||||
assert_message_printed("info/XYZ");
|
||||
assert_message_not_printed("info/XXX");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue