1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
//! A configurable logging library for Rust
//!
//! The `hclog` (highly configurable log) library for Rust is designed to be a highly configurable
//! logging solution. Its primary goal is to offer a customizable logging backend that caters to
//! individual user needs, providing detailed control over logging options.
//! Users have the flexibility to select from a variety of logging backends, specify the information
//! included in log messages, and choose the desired module or logging level.
//!
//! # Idea of this crate
//!
//! Existing log crates often provide a limited set of logging levels, such as `error`, `info`, and
//! `debug`. While this may be sufficient for smaller applications, larger applications - especially
//! those with modularized environments - require more precise control over logging output. In a
//! modularized environment, different components like the GUI, network stack and storage subsystem
//! generate log events, making it challenging to manage and analyze logs.
//! A limited set of logging levels can lead to inaccurate, misleading or a massive amount of log
//! messages which are not helpful for debugging or monitoring. A more fine-grained control over
//! the desired log level can increase the quality of the log messages and reduce the complexity of
//! the log output.
//!
//! hclog is designed to address this issue(s) by providing fine-grained control over logging
//! output. Each module has it's own scope with its own LogKeys, which can be configured and
//! turned on and off individually.
//! This allows developers to tailor logging settings to specific components, ensuring that log
//! events are accurate, informative, and actionable. For example, a web application might define
//! separate scopes for its web server, database, and authentication modules, each with its own
//! logging configuration.
//!
//! # Concept of this crate
//!
//! This library's core concept is a key-based logging system, where each logger or logging backend
//! is uniquely identified by a [`LogKey`]. Each LogKey can be individually configured with its own
//! logging [`Level`] and facade variant [`FacadeVariant`].
//!
//! To avoid naming conflicts between different modules or crates, `LogKey`s are organized within a
//! scope, which serves as a namespace or container. When an application integrates multiple
//! libraries, each defines its own set of LogKeys, which are stored within separate scopes.
//! This hierarchical structure allows for organized and collision-free logging management.
//! Each `LogKey` is a unique identifier which can be configured on his own. Note that all
//! identifiers should be exclusive to the scope and not be used in any other scopes.
//!
//! Assume a sample application with three modules A, B and C that look like this:
//!
//! ```none
//! +---------------+
//! | Application |
//! +-------+-------+
//! |
//! | +---+---+ +---+---+ +---+---+
//! +--------+ Mod A +----+ Mod B +----+ Mod C +
//! | +---+---+ +---+---+ +---+---+
//! | | | |
//! +-------+------------+------------+------------+-----+
//! | App Scope | ModA Scope | ModB Scope | ModC Scope |
//! +-------------+------------+------------+------------+
//! | AA | MAA | MBA | MCA |
//! | AB | MAB | MBB | MCB |
//! | AC | MAC | MBC | MCC |
//! | AD | MAD | MBC | MCD |
//! +----------------------------------------------------+
//! ```
//! The usage and examples below show how a sample imlementation of this structure could look like.
//!
//! # Usage
//!
//! The basic logging functionality is provided by the [`lI!`], [`lD1!`], [`lE!`] and so on macros.
//! These macros expect a `LogKey` - as defined on initialization - and a format string similar to
//! common `print!` macros in rust. The `LogKey` is used to identify the logger and the format
//! string is the message to be printed. Taken the App Scope from the example above the minimal
//! usage would look like this:
//!
//! ```rust
//! # use hclog::Level;
//! # use hclog_macros::HCLog;
//! # #[derive(HCLog, Copy, Clone)]
//! # enum AppScope { AA, AB, AC, AD }
//! # AppScope::init_with_defaults("Keys").unwrap();
//! # use AppScope::*;
//! hclog::lI!(AA, "This is an info message");
//! hclog::lD5!(AB, "This is a debug message with level {}", Level::Debug5);
//! ```
//! Avoid writing expressions with side-effects in log statements. They may not be evaluated.
//!
//! ## In Libraries
//!
//! The example above just shows the basic usage of the logging macros without the actual
//! initialization of those keys. The following example shows how to initialize the library and
//! define the `LogKey`s for the `ModA` library:
//!
//! ```
//! use hclog::{Scope, LogKey, Level, FacadeVariant, options::Options, Result};
//!
//! #[derive(Copy, Clone, Debug)]
//! enum ModAKeys {
//! MAA,
//! MAB,
//! MAC,
//! MAD,
//! }
//! use ModAKeys::*;
//!
//! impl std::fmt::Display for ModAKeys {
//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//! write!(f, "{}", match self {
//! Self::MAA => "MAA",
//! Self::MAB => "MAB",
//! Self::MAC => "MAC",
//! Self::MAD => "MAD",
//! })
//! }
//! }
//!
//! impl Scope for ModAKeys {
//! fn default_level() -> Level { Level::Info }
//! fn init<S: std::fmt::Display>(
//! name: S, level: Level, facade: FacadeVariant, options: Options
//! ) -> Result<()> {
//! hclog::init::<Self, S>(name, level, facade, options)?;
//! hclog::add_submodules(&[Self::MAA, Self::MAB, Self::MAC, Self::MAD])
//! }
//! }
//!
//! impl LogKey for ModAKeys {
//! fn log_key(&self) -> usize {
//! match self {
//! Self::MAA => 0,
//! Self::MAB => 1,
//! Self::MAC => 2,
//! Self::MAD => 3,
//! }
//! }
//! }
//!
//! fn do_log() {
//! hclog::lI!(MAA, "this is a info message in Library Scope");
//! hclog::LD10!(MAA, "this is a debug message in Library Scope");
//! }
//!
//! fn init_mod_a(level: Level, facade: FacadeVariant, options: Options) -> Result<()> {
//! /* main initialization part of the library */
//! ModAKeys::init("ModA", level, facade, options)?;
//! Ok(())
//! }
//! ```
//!
//! The `LogKey`s are defined as an enum implementing the `LogKey` and `Scope` traits. Implementing
//! the `Scope` trait is necessary to initialize the library - if not already done - and also
//! creates the namespace for this set of `LogKey`s. The `LogKey` trait is used to define the
//! unique identifier for the loggers in this scope.
//! Additionally, the `Display` trait is required - as a bound by [`LogKey`] - to display the name
//! in the log output.
//!
//! ## In Applications/executables
//!
//! Taking the example above a sample application could look like this:
//!
//! _Note: The example below uses the same [`Level`] and [`FacadeVariant`] for the application
//! and the libraries. This is not necessary and can be configured individually._
//!
//!
//! ```
//! use hclog::{Scope, LogKey, Level, FacadeVariant, options::Options, Result};
//! // use moda; // import the 'module' above
//!
//! #[derive(Copy, Clone, Debug)]
//! enum AppKeys {
//! AA,
//! AB,
//! AC,
//! AD,
//! }
//! use AppKeys::*;
//!
//! impl std::fmt::Display for AppKeys {
//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//! write!(f, "{}", match self {
//! Self::AA => "AA",
//! Self::AB => "AB",
//! Self::AC => "AC",
//! Self::AD => "AD",
//! })
//! }
//! }
//!
//! impl Scope for AppKeys {
//! fn init<S: std::fmt::Display>(
//! name: S, level: Level, facade: FacadeVariant, options: Options
//! ) -> Result<()> {
//! hclog::init::<Self, S>(name, level, facade, options)?;
//! hclog::add_submodules(&[Self::AA, Self::AB, Self::AC])?;
//! // call initialization routine in the library
//! // moda::init_mod_a(level, facade, options)?;
//! Ok(())
//! }
//! }
//!
//! impl LogKey for AppKeys {
//! fn log_key(&self) -> usize {
//! match self {
//! Self::AA => 0,
//! Self::AB => 1,
//! Self::AC => 2,
//! Self::AD => 3,
//! }
//! }
//! }
//!
//! fn main() {
//! AppKeys::init("MyApp", Level::Debug1, FacadeVariant::StdOut, Options::default()).unwrap();
//!
//! // moda::do_log(); // logs in the scope of the library
//! hclog::lI!(AA, "this is a info message in App Scope");
//! }
//! ```
//! Applications or executables also define their own set of [`LogKey`]s which are used to log
//! messages within the scope of the application. The initialization of the application is done
//! by calling the `init` function of the [`Scope`] implementation of the [`LogKey`] type.
//! The application can also initialize the loggers of the libraries it uses.
//!
//! If a user of this Application wants to get just the logging output of librarys `ModA` LogKey
//! `MAA` he can either initialize the library with a desired level and disable logging in the
//! application or provide a commandline option to filter the output of the application which might
//! look like this:
//! ```
//! [foo ~]# ./myapp -l "MAA:debug1"
//! ```
//! This would print the `lI!` message in the library but not the `lD10!` message.
//!
//! ## Usage with crate `hclog_macros`
//!
//! The `hclog_macros` crate provides an attributable derive macro for the usage with this crate.
//! It allows you to derive all traits necessary to initialize the library and configure default
//! values at compile time.
//! For more informations consult the documentation of the `hclog_macros` crate.
//!
//! ```rust
//! use hclog::{Level, FacadeVariant};
//! use hclog_macros::HCLog;
//!
//! #[derive(HCLog, Copy, Clone)]
//! #[hclog(default_level = Level::Info, default_facade = FacadeVariant::StdOut)]
//! enum ModBKeys {
//! #[hclog(name = "A", level = Level::Debug1)]
//! MBA,
//! #[hclog(name = "B", facade = FacadeVariant::StdErr)]
//! MBB,
//! #[hclog(name = "C")]
//! MBC,
//! #[hclog(name = "D")]
//! MBD,
//! }
//!
//! use ModBKeys::*;
//!
//! fn main() {
//! ModBKeys::init_with_defaults("MyLogKeys").unwrap();
//! hclog::lD1!(MBB, "this won't get logged because of lvl Info for Key DB");
//! hclog::lD1!(MBA, "this will get logged because of lvl Debug1 for Key DA");
//! hclog::lE!(MBB, "this will be logged to stderr");
//! }
//! ```
//!
//! # Warning
//!
//! The library internal context may be init only once.
//!
//! # Crate Feature Flags
//!
//! The following feature flags are available for this crate. They are configured in your Cargo.toml:
//!
//! * `std`: Enabled by default. This flag does not enable any additional features.
//! * `derive`: This flag enables the derive macro for the `HCLog` trait.
//!
//! ```toml
//! [dependencies]
//! hclog = { version = "0.1", features = ["derive"] }
//! ```
//!
//! # Version compatibility
//!
//! This crate is currently compatible with Rust 1.74.1 and later. We will try to keep this
//! compatibility as long as possible. If you need a specific version of Rust please open an
//! issue on the GitHub repository. Hence this is still a version 0.1.0 crate the API is not
//! stable and might change in the future. We will try to keep the changes as minimal as possible
//! and provide a migration guide or compability layer if necessary.
//!
//! [crate-log]: https://docs.rs/log/latest/log/
//! [crate-stdext]: https://docs.rs/stdext/latest/stdext/
extern crate log;
// required to derive trait in doc tests which would fail to compile otherwise
// NOTE: doc tests / examples hide the derive by intention. This is a workaround to make it work.
extern crate hclog_macros;
use Display;
pub use crate;
pub use crateInternalLogKeys;
pub use crateScopeKey;
pub use crateFacadeVariant;
pub use crateLevel;
pub use crate*;
// library internal imports
use crate*;
/// Alias for the Index of the Scope in the context
///
/// This demands that passed [`LogKey`] implementors are `#[repr(usize)]` which is
/// currently the default.
pub type ContextKey = usize;
/// Initialization trait for the log scope
///
/// Trait to initialize to library which is implemented on a set of [`LogKey`]s. It can
/// either be implemented manually or derived from the `HCLog` derive macro from the
/// `hclog_macros` crate.
/// If the [`LOGCOMPAT`] option is set the compatibility logger is initialized as well.
///
/// A type implementing this trait has to implement [`Send`], [`Sync`] and [`Copy`].
///
/// ## What is a Scope?
///
/// The [`Scope`] is a container to store all initialized [`LogKey`]s. Each Scope is assigned a
/// unique [`ScopeKey`] which is used to crate a namespace for [`LogKey`]s in the context.
/// This way can be ensured that there are no identifier collisions in different crates or modules
/// when using the library.
///
/// A call to [`init`] will fetch a new [`ScopeKey`] from the context and initialize the loggers
/// within this container. The [`ScopeKey`] itself is constant at runtime and can not be changed
/// because it is used as an Index in the context.
///
/// ## Options of the Scope
///
/// On initialization default [`Level`], [`FacadeVariant`] and [`Options`] can be set for the
/// [`Scope`]. This values are passed to each newly initialized [`LogKey`] in this [`Scope`].
/// If the [`LogKey`] is initialized with a different set of options, the default options are
/// ignored.
///
/// # Examples
///
/// ### Manual Implementation
///
/// ```compile_fail
/// use hclog::{Scope, Level, FacadeVariant, Options, Result};
///
/// #[derive(Copy, Clone, Debug)]
/// enum MyLogKeys {
/// Foo,
/// Bar,
/// Baz,
/// }
///
/// // This example won't compile because the LogKeys and std::fmt::Display traits
/// // are not implemented but reqiuired. This is by intention to show the minimal
/// // implementation of the Scope trait.
///
/// impl Scope for MyLogKeys {
/// fn init<S: std::fmt::Display>(
/// name: S, level: Level, facade: FacadeVariant, options: Options
/// ) -> Result<()> {
/// hclog::init::<Self, S>(name, level, facade, options)?;
/// hclog::add_submodules(&[Self::Foo, Self::Bar, Self::Baz])
/// }
/// }
///
/// ```
///
/// ### Derive from `HCLog` via crate `hclog_macros`
///
/// For a detailed usage of the derive macro see the documentation of the crate `hclog_macros`.
///
/// ```rust
/// use hclog_macros::HCLog;
///
/// #[derive(HCLog, Copy, Clone)]
/// enum MyLogKeys {
/// Foo,
/// Bar,
/// Baz,
/// }
/// ```
///
/// # Errors
///
/// The initialzation of the log scope can fail if:
/// - the log scope is already initialized
/// - the initialization of the log scope fails
/// - the [`LOGCOMPAT`] option is set and the initialization of the
/// compatibility logger fails
///
/// # Panics
///
/// The `init` or `init_with_defaults` function might panic if the internal `RwLock` is already
/// held by the current thread as documented in [`std::sync::RwLock::write`].
///
/// Trait for the LogKey
///
/// ## What is a LogKey?
///
/// A [`LogKey`] is a unique identifier for a set of loggers. It is used to access the loggers
/// in the context. The [`LogKey`] is used to initialize the loggers with a set of default values
/// like the [`Level`], [`FacadeVariant`] and [`Options`].
///
/// A type implementing `LogKey` must also implement the [`Scope`] and [`Display`] traits. The `Display`
/// trait is used to display the name of the `LogKey` in the log output. The `Scope` trait is used
/// store the associated `LogKey` in a defined namespace container.
///
/// # Usage
///
/// The basic usage of those Keys is to pass them to hclog provided functions and macros as an
/// unique identifier to the logger like this:
///
/// ```rust
/// use hclog::{Level, lEM};
/// # use hclog_macros::HCLog;
/// # #[derive(HCLog, Copy, Clone, Debug)]
/// enum MyLogKeys { LA }
///
/// use MyLogKeys::LA;
///
/// # MyLogKeys::init_with_defaults("MyLogKeys").unwrap();
/// let _ = hclog::set_level(LA, Level::Emerg);
/// lEM!(LA, "This is an emergency message");
/// ```
///
/// The `MyLogKeys` type is taken from the [`example`](trait@LogKey#manual-implementation) below.
///
/// # Examples
///
/// There are two ways how this trait can be implemented. Either manually or via the `HCLog` derive
/// macro from the `hclog_macros` crate:
///
/// ### Manual Implementation
///
/// ```compile_fail
/// use hclog::LogKey;
///
/// #[derive(Copy, Clone, Debug)]
/// enum MyLogKeys {
/// LA,
/// LB,
/// LC,
/// }
/// // Implement the Scope trait for the LogKeys is missing. Note that both
/// // traits (Scope + LogKey) have to be implemented for the LogKeys. Therefore
/// // this example won't compile
///
/// // Implement Display for the LogKeys because LogKey demands it
/// impl std::fmt::Display for MyLogKeys {
/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// write!(f, "{}", match self {
/// Self::Foo => "foo",
/// Self::Bar => "bar",
/// Self::Baz => "baz",
/// })
/// }
/// }
///
/// // Implement the LogKey trait for the LogKeys
/// impl LogKey for MyLogKeys {
/// fn log_key(&self) -> ContextKey {
/// match self {
/// Self::LA => 0,
/// Self::LB => 1,
/// Self::LC => 2,
/// }
/// }
/// }
/// ```
///
/// ### Derive from `HCLog` via crate `hclog_macros`
///
/// For a detailed usage of the derive macro see the documentation of the crate `hclog_macros`.
///
/// ```rust
/// use hclog_macros::HCLog;
///
/// #[derive(HCLog, Copy, Clone)]
/// enum MyLogKeys {
/// Foo,
/// Bar,
/// Baz,
/// }
/// ```
///