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
//! Support for structured logging.
//!
//! # Overview
//!
//! When the `tracing` feature is activated, each tracing event or span emitted
//! by a model is wrapped in a [`tracing::Span`] with the following metadata:
//!
//! - name: `model`,
//! - target: `nexosim`,
//! - verbosity level: [`Level::INFO`](tracing::Level::INFO),
//! - a unique field called `name` that identifies the model path provided in
//! [`SimInit::add_model`](crate::simulation::SimInit::add_model).
//!
//! The emission of `model` spans can be readily used for [event
//! filtering](#event-filtering-examples), using for instance the
//! `tracing_subscriber::fmt` subscriber. By default, however, this subscriber
//! will timestamp events with the wall clock time. Because it is often
//! desirable to log events using the simulation time instead of (or on top of)
//! the wall clock time, this module provides a custom [`SimulationTime`] timer
//! compatible with `tracing_subscriber::fmt`.
//!
//!
//! # Configuration
//!
//! Using the `tracing-subscriber` crate, simulation events can be logged to
//! standard output by placing the following call anywhere before
//! [`SimInit::init`](crate::simulation::SimInit::init):
//!
//! ```
//! tracing_subscriber::fmt::init();
//! ```
//!
//! Logging from a model is then a simple matter of using the `tracing` macros,
//! for instance:
//!
//! ```
//! use tracing::warn;
//!
//! pub struct MyModel { /* ... */ }
//!
//! impl MyModel {
//! pub fn some_input_port(&mut self, _some_parameter: i32) {
//! // ...
//! warn!("something happened inside the simulation");
//! // ...
//! }
//! }
//! ```
//!
//! However, this will stamp events with the system time rather than the
//! simulation time. To use simulation time instead, a dedicated timer can be
//! configured:
//!
//! ```
//! use nexosim::tracing::SimulationTime;
//!
//! tracing_subscriber::fmt()
//! .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
//! .with_timer(SimulationTime::with_system_timer())
//! .init();
//! ```
//!
//! This timer will automatically revert to system time stamping for tracing
//! events generated outside of simulation models, e.g.:
//!
//! ```text
//! [2001-02-03 04:05:06.789012345] WARN model{name="my_model"}: my_simulation: something happened inside the simulation
//! 2024-09-10T14:39:24.670921Z INFO my_simulation: something happened outside the simulation
//! ```
//!
//! Alternatively, `SimulationTime::with_system_timer_always` can be used to
//! always prepend the system time even for simulation events:
//!
//! ```text
//! 2024-09-10T14:39:22.124945Z [2001-02-03 04:05:06.789012345] WARN model{name="my_model"}: my_simulation: something happened inside the simulation
//! 2024-09-10T14:39:24.670921Z INFO my_simulation: something happened outside the simulation
//! ```
//!
//!
//! # Event filtering examples
//!
//! Note that event filtering based on the `RUST_LOG` environment variable
//! requires the `env-filter` feature of the
//! [`tracing-subscriber`][tracing_subscriber] crate.
//!
//! The following `RUST_LOG` directive could be used to only let warnings and
//! errors pass through but still see model span information (which is emitted
//! as info):
//!
//! ```text
//! $ RUST_LOG="warn,[model]=info" cargo run --release my_simulation
//! [2001-01-01 00:00:06.000000000] WARN model{name="kettle"}: my_simulation: water is boiling
//! [2001-01-01 00:01:36.000000000] WARN model{name="timer"}: my_simulation: ring ring
//! [2001-01-01 00:01:36.000000000] WARN model{name="kettle"}: my_simulation: water is ready
//! ```
//!
//! In order to see warnings or errors for the `kettle` model only, this
//! directive could be modified as follows:
//!
//! ```text
//! $ RUST_LOG="[model{name=kettle}]=warn" cargo run --release my_simulation
//! [2001-01-01 00:00:06.000000000] WARN model{name="kettle"}: my_simulation: water is boiling
//! [2001-01-01 00:01:36.000000000] WARN model{name="kettle"}: my_simulation: water is ready
//! ```
//!
//! If the `model` span name collides with that of spans defined outside
//! `nexosim`, the above filters can be made more specific using
//! `nexosim[model]` instead of just `[model]`.
//!
//!
//! # Customization
//!
//! The `tracing-subscriber` crate allows for customization such as logging to
//! files or formatting logs with JSON.
//!
//! Further customization is possible by implementing a
//! `tracing_subscriber::layer::Layer` or a dedicated `tracing::Subscriber`.
use fmt;
use Writer;
use ;
use crateSIMULATION_CONTEXT;
/// A timer that can be used in conjunction with the
/// [`tracing-subscriber`](mod@tracing_subscriber) crate to log events using the
/// simulation time instead of (or on top of) the wall clock time.
///
/// See the [module-level documentation](crate::tracing) for more details.