Skip to content

Commit f45cac2

Browse files
committed
Development Tools WIP
1 parent 203b063 commit f45cac2

19 files changed

+532
-454
lines changed

src/SUMMARY.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@
1818
- [Data Structures](data_structures.md)
1919
- [Constants](data_structures/constant.md)
2020
- [Custom](data_structures/custom.md)
21+
- [Development Tools](development_tools.md)
22+
- [Debugging](development_tools/debugging.md)
23+
- [Log Messages](development_tools/debugging/log.md)
24+
- [Configure Logging](development_tools/debugging/config_log.md)
25+
- [Versioning](development_tools/versioning.md)
26+
- [Build Time Tooling](development_tools/build_tools.md)
2127
- [Basics](basics.md)
2228
- [Encoding](encoding.md)
2329
- [Networking](net.md)
2430
- [Application development](app.md)
2531
- [Logging](logging.md)
26-
- [Build Time Tooling](build_tools.md)

src/basics.md

-2
Original file line numberDiff line numberDiff line change
@@ -689,8 +689,6 @@ fn run() -> Result<()> {
689689

690690
{{#include cryptography/encryption/pbkdf2.md}}
691691

692-
693-
[ex-bitflags]: #ex-bitflags
694692
{{#include data_structures/custom/bitfield.md}}
695693

696694
[ex-random-file-access]: #ex-random-file-access

src/development_tools.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Development Tools
2+
3+
| Recipe | Crates | Categories |
4+
|--------|--------|------------|
5+
| [Log a debug message to the console][ex-log-debug] | [![log-badge]][log] [![env_logger-badge]][env_logger] | [![cat-debugging-badge]][cat-debugging] |
6+
| [Log an error message to the console][ex-log-error] | [![log-badge]][log] [![env_logger-badge]][env_logger] | [![cat-debugging-badge]][cat-debugging] |
7+
| [Enable log levels per module][ex-log-mod] | [![log-badge]][log] [![env_logger-badge]][env_logger] | [![cat-debugging-badge]][cat-debugging] |
8+
| [Log to stdout instead of stderr][ex-log-stdout] | [![log-badge]][log] [![env_logger-badge]][env_logger] | [![cat-debugging-badge]][cat-debugging] |
9+
| [Log messages with a custom logger][ex-log-custom-logger] | [![log-badge]][log] | [![cat-debugging-badge]][cat-debugging] |
10+
| [Use a custom environment variable to set up logging][ex-log-env-variable] | [![log-badge]][log] [![env_logger-badge]][env_logger] | [![cat-debugging-badge]][cat-debugging] |
11+
| [Include timestamp in log messages][ex-log-timestamp] | [![log-badge]][log] [![env_logger-badge]][env_logger] [![chrono-badge]][chrono] | [![cat-debugging-badge]][cat-debugging] |
12+
| [Log to the Unix syslog][ex-log-syslog] | [![log-badge]][log] [![syslog-badge]][syslog] | [![cat-debugging-badge]][cat-debugging] |
13+
| [Log messages to a custom location][ex-log-custom] | [![log-badge]][log] [![log4rs-badge]][log4rs] | [![cat-debugging-badge]][cat-debugging] |
14+
15+
[ex-log-debug]: development_tools/debugging/log.html#log-a-debug-message-to-the-console

src/build_tools.md renamed to src/development_tools/build_tools.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ fn main(){
177177

178178
[![cc-badge]][cc] [![cat-development-tools-badge]][cat-development-tools]
179179

180-
It is simple to build bundled C code with custom defines using [`cc::Build::define`].
180+
It is simple to build bundled C code with custom defines using [`cc::Build::define`].
181181
It takes an [`Option`] value, so it is possible to create defines such as `#define APP_NAME "foo"`
182182
as well as `#define WELCOME` (pass `None` as the value for a value-less defne). This example builds
183183
a bundled C file with dynamic defines set in `build.rs` and prints "**Welcome to foo - version 1.0.2**"
@@ -238,7 +238,7 @@ fn main(){
238238
}
239239
```
240240

241-
{{#include links.md}}
241+
{{#include ../links.md}}
242242

243243
<!-- Other Reference -->
244244

src/development_tools/debugging.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Debugging
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Configure Logging
2+
3+
{{#include config_log/log-mod.md}}
4+
5+
{{#include config_log/log-env-variable.md}}
6+
7+
{{#include config_log/log-timestamp.md}}
8+
9+
{{#include config_log/log-custom.md}}
10+
11+
{{#include ../../links.md}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<a name="ex-log-custom"></a>
2+
## Log messages to a custom location
3+
4+
[![log-badge]][log] [![log4rs-badge]][log4rs] [![cat-debugging-badge]][cat-debugging]
5+
6+
Configures log to be output into custom location with [log4rs]. [log4rs] can use either an external YAML file or a programmatically constructed configuration.
7+
8+
Firstly creates the log configuration with [`log4rs::append::file::FileAppender`]
9+
using a custom pattern from [`log4rs::encode::pattern`].
10+
11+
Secondly assigns it to the [`log4rs::config::Config`] which has a root appender that uses the previously created `logfile` appender. Subsequently sets the default [`log::LogLevelFilter`] so that any logs with `Info` level or higher will be sent to the logger.
12+
13+
```rust,no_run
14+
# #[macro_use]
15+
# extern crate error_chain;
16+
#[macro_use]
17+
extern crate log;
18+
extern crate log4rs;
19+
20+
use log::LogLevelFilter;
21+
use log4rs::append::file::FileAppender;
22+
use log4rs::encode::pattern::PatternEncoder;
23+
use log4rs::config::{Appender, Config, Root};
24+
#
25+
# error_chain! {
26+
# foreign_links {
27+
# Io(std::io::Error);
28+
# LogConfig(log4rs::config::Errors);
29+
# SetLogger(log::SetLoggerError);
30+
# }
31+
# }
32+
33+
fn run() -> Result<()> {
34+
let logfile = FileAppender::builder()
35+
.encoder(Box::new(PatternEncoder::new("{l} - {m}\n")))
36+
.build("log/output.log")?;
37+
38+
let config = Config::builder()
39+
.appender(Appender::builder().build("logfile", Box::new(logfile)))
40+
.build(Root::builder()
41+
.appender("logfile")
42+
.build(LogLevelFilter::Info))?;
43+
44+
log4rs::init_config(config)?;
45+
46+
info!("Hello, world!");
47+
48+
Ok(())
49+
}
50+
#
51+
# quick_main!(run);
52+
```
53+
54+
[`log4rs::append::file::FileAppender`]: https://docs.rs/log4rs/*/log4rs/append/file/struct.FileAppender.html
55+
[`log4rs::config::Config`]: https://docs.rs/log4rs/*/log4rs/config/struct.Config.html
56+
[`log4rs::encode::pattern`]: https://docs.rs/log4rs/*/log4rs/encode/pattern/index.html
57+
[`log::LogLevelFilter`]: https://doc.rust-lang.org/log/log/enum.LogLevelFilter.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<a name="ex-log-env-variable"></a>
2+
## Use a custom environment variable to set up logging
3+
4+
[![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging]
5+
6+
Logging is configured with [`LogBuilder`].
7+
8+
[`LogBuilder::parse`] parses `MY_APP_LOG`
9+
environmental variable contents in the form of [`RUST_LOG`] syntax.
10+
Then [`LogBuilder::init`] initializes the logger.
11+
All these steps are normally done internally by [`env_logger::init`].
12+
13+
```rust
14+
# #[macro_use]
15+
# extern crate error_chain;
16+
#[macro_use]
17+
extern crate log;
18+
extern crate env_logger;
19+
20+
use std::env;
21+
use env_logger::LogBuilder;
22+
23+
# error_chain! {
24+
# foreign_links {
25+
# EnvLogger(log::SetLoggerError);
26+
# }
27+
# }
28+
#
29+
fn run() -> Result<()> {
30+
LogBuilder::new()
31+
.parse(&env::var("MY_APP_LOG").unwrap_or_default())
32+
.init()?;
33+
34+
info!("informational message");
35+
warn!("warning message");
36+
error!("this is an error {}", "message");
37+
38+
Ok(())
39+
}
40+
#
41+
# quick_main!(run);
42+
```
43+
44+
[`env_logger::init`]: https://doc.rust-lang.org/log/env_logger/fn.init.html
45+
[`LogBuilder`]: https://doc.rust-lang.org/log/env_logger/struct.Builder.html
46+
[`LogBuilder::init`]: https://doc.rust-lang.org/log/env_logger/struct.LogBuilder.html#method.init
47+
[`LogBuilder::parse`]: https://doc.rust-lang.org/log/env_logger/struct.LogBuilder.html#method.parse
48+
[`RUST_LOG`]: https://doc.rust-lang.org/log/env_logger/#enabling-logging
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<a name="ex-log-mod"></a>
2+
## Enable log levels per module
3+
4+
[![log-badge]][log] [![env_logger-badge]][env_logger] [![cat-debugging-badge]][cat-debugging]
5+
6+
Creates two modules `foo` and nested `foo::bar` with logging directives
7+
controlled separately with [`RUST_LOG`] environmental variable.
8+
9+
```rust
10+
# #[macro_use]
11+
# extern crate error_chain;
12+
#[macro_use]
13+
extern crate log;
14+
extern crate env_logger;
15+
16+
mod foo {
17+
mod bar {
18+
pub fn run() {
19+
warn!("[bar] warn");
20+
info!("[bar] info");
21+
debug!("[bar] debug");
22+
}
23+
}
24+
25+
pub fn run() {
26+
warn!("[foo] warn");
27+
info!("[foo] info");
28+
debug!("[foo] debug");
29+
bar::run();
30+
}
31+
}
32+
#
33+
# error_chain! {
34+
# foreign_links {
35+
# SetLogger(log::SetLoggerError);
36+
# }
37+
# }
38+
39+
fn run() -> Result<()> {
40+
env_logger::init()?;
41+
warn!("[root] warn");
42+
info!("[root] info");
43+
debug!("[root] debug");
44+
foo::run();
45+
46+
Ok(())
47+
}
48+
#
49+
# quick_main!(run);
50+
```
51+
52+
[`env_logger`][env_logger] output is controlled by [`RUST_LOG`] environmental
53+
variable on per module basis with comma separated entries in format `path::to::module=log_level`.
54+
Running the `test` application as follows:
55+
56+
```bash
57+
RUST_LOG="warn,test::foo=info,test::foo::bar=debug" ./test
58+
```
59+
60+
Sets the default [`log::LogLevel`] to `warn`, module's `foo` and module's `foo::bar`
61+
respectively to `info` and `debug`. The output is:
62+
63+
```bash
64+
WARN:test: [root] warn
65+
WARN:test::foo: [foo] warn
66+
INFO:test::foo: [foo] info
67+
WARN:test::foo::bar: [bar] warn
68+
INFO:test::foo::bar: [bar] info
69+
DEBUG:test::foo::bar: [bar] debug
70+
```
71+
72+
[`log::LogLevel`]: https://doc.rust-lang.org/log/log/enum.LogLevel.html
73+
[`RUST_LOG`]: https://doc.rust-lang.org/log/env_logger/#enabling-logging
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<a name="ex-log-timestamp"></a>
2+
## Include timestamp in log messages
3+
4+
[![log-badge]][log] [![env_logger-badge]][env_logger] [![chrono-badge]][chrono] [![cat-debugging-badge]][cat-debugging]
5+
6+
Creates a custom logger configuration with [`LogBuilder`].
7+
Each log entry calls [`Local::now`] to get the current [`DateTime`] in local timezone and uses [`DateTime::format`] with [`strftime::specifiers`] to format a timestamp used in the final log.
8+
9+
The example calls [`LogBuilder::format`] to set a closure which formats each
10+
message text with timestamp, [`LogRecord::level`] and body ([`LogRecord::args`]).
11+
12+
```rust
13+
# #[macro_use]
14+
# extern crate error_chain;
15+
#[macro_use]
16+
extern crate log;
17+
extern crate env_logger;
18+
extern crate chrono;
19+
20+
use std::env;
21+
use env_logger::LogBuilder;
22+
use chrono::Local;
23+
24+
#
25+
# error_chain! {
26+
# foreign_links {
27+
# SetLogger(log::SetLoggerError);
28+
# }
29+
# }
30+
31+
fn run() -> Result<()> {
32+
LogBuilder::new()
33+
.format(|record| {
34+
format!("{} [{}] - {}",
35+
Local::now().format("%Y-%m-%dT%H:%M:%S"),
36+
record.level(),
37+
record.args())
38+
})
39+
.parse(&env::var("MY_APP_LOG").unwrap_or_default())
40+
.init()?;
41+
42+
warn!("warn");
43+
info!("info");
44+
debug!("debug");
45+
Ok(())
46+
}
47+
#
48+
# quick_main!(run);
49+
```
50+
Calling `MY_APP_LOG="info" cargo run` will result in similar output:
51+
```
52+
2017-05-22T21:57:06 [WARN] - warn
53+
2017-05-22T21:57:06 [INFO] - info
54+
```
55+
56+
[`DateTime::format`]: https://docs.rs/chrono/*/chrono/datetime/struct.DateTime.html#method.format
57+
[`DateTime`]: https://docs.rs/chrono/*/chrono/datetime/struct.DateTime.html
58+
[`Local::now`]: https://docs.rs/chrono/*/chrono/offset/local/struct.Local.html#method.now
59+
[`LogBuilder`]: https://doc.rust-lang.org/log/env_logger/struct.Builder.html
60+
[`LogBuilder::format`]: https://doc.rust-lang.org/log/env_logger/struct.LogBuilder.html#method.format
61+
[`LogRecord::args`]: https://doc.rust-lang.org/log/log/struct.LogRecord.html#method.args
62+
[`LogRecord::level`]: https://doc.rust-lang.org/log/log/struct.LogRecord.html#method.level
63+
[`strftime::specifiers`]: https://docs.rs/chrono/*/chrono/format/strftime/index.html#specifiers
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Log Messages
2+
3+
{{#include log/log-debug.md}}
4+
5+
{{#include log/log-error.md}}
6+
7+
{{#include log/log-stdout.md}}
8+
9+
{{#include log/log-custom-logger.md}}
10+
11+
{{#include log/log-syslog.md}}
12+
13+
{{#include ../../links.md}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<a name="ex-log-custom-logger"></a>
2+
## Log messages with a custom logger
3+
4+
[![log-badge]][log] [![cat-debugging-badge]][cat-debugging]
5+
6+
Implements a custom logger `ConsoleLogger` which prints to stdout.
7+
In order to use the logging macros, `ConsoleLogger` implements
8+
the [`log::Log`] trait and has to be installed via [`log::set_logger`].
9+
10+
```rust
11+
# #[macro_use]
12+
# extern crate error_chain;
13+
#[macro_use]
14+
extern crate log;
15+
16+
use log::{LogRecord, LogLevel, LogMetadata, LogLevelFilter};
17+
18+
struct ConsoleLogger;
19+
20+
impl log::Log for ConsoleLogger {
21+
fn enabled(&self, metadata: &LogMetadata) -> bool {
22+
metadata.level() <= LogLevel::Info
23+
}
24+
25+
fn log(&self, record: &LogRecord) {
26+
if self.enabled(record.metadata()) {
27+
println!("Rust says: {} - {}", record.level(), record.args());
28+
}
29+
}
30+
}
31+
#
32+
# error_chain! {
33+
# foreign_links {
34+
# SetLogger(log::SetLoggerError);
35+
# }
36+
# }
37+
38+
fn run() -> Result<()> {
39+
log::set_logger(|max_log_level| {
40+
max_log_level.set(LogLevelFilter::Info);
41+
Box::new(ConsoleLogger)
42+
})?;
43+
44+
info!("hello log");
45+
warn!("warning");
46+
error!("oops");
47+
Ok(())
48+
}
49+
#
50+
# quick_main!(run);
51+
```

0 commit comments

Comments
 (0)