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
//! Logging utilities for `dnet` transports.
use std::{any::type_name, task::Poll};
use tracing::{debug, error, info, trace, trace_span, warn, Span};
/// Trait implemented by `dnet` transports that support logging.
pub trait Logging {
/// Short human-readable type of `dnet` the transport.
const KIND: &'static str;
/// Execute closure with transport's logger.
fn with_logger<F, R>(&self, f: F) -> R
where
F: FnOnce(&Logger) -> R;
/// Execute closure with transport's logger (mutable).
fn with_logger_mut<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Logger) -> R;
/// Set transport name (for logging purposed).
fn set_logging_name(&mut self, name: &str) {
self.with_logger_mut(|logger| logger.set_transport_name(Some(name.to_string())));
}
/// Get transport name (for logging purposed).
fn get_logging_name(&mut self) -> Option<String> {
self.with_logger_mut(|logger| logger.get_transport_name().map(|name| name.to_string()))
}
/// Enable logging for this transport.
fn enable_logging(&mut self) {
self.with_logger_mut(|logger| logger.enable());
}
/// Disable logging for this transport.
fn disable_logging(&mut self) {
self.with_logger_mut(|logger| logger.disable());
}
/// Is logging enabled for this transport.
fn is_logging_enabled(&self) -> bool {
self.with_logger(|logger| logger.is_enabled())
}
}
/// Logging utility for `dnet` transports.
pub struct Logger {
kind: String,
name: Option<String>,
enabled: bool,
}
impl Logger {
/// Create new logger for transport.
pub fn new<T>() -> Self
where
T: Logging,
{
let kind = T::KIND.to_string();
let name = None;
let enabled = false;
Logger {
kind,
name,
enabled,
}
}
/// Create new logger for transport that already has a name.
///
/// Usually `dnet` transports don't have names, but when they do
/// you may use this constructor to make transport's logical name the
/// same as the one used for logging purposes.
///
/// Note that logging name may still be changed later by the transport user
/// and at that point logical name and logging name may be different.
pub fn new_for_already_named<T>(transport_name: &str) -> Self
where
T: Logging,
{
let kind = T::KIND.to_string();
let name = Some(transport_name.to_string());
let enabled = false;
Logger {
kind,
name,
enabled,
}
}
/// Log that the transport was opened successfully.
///
/// Note: not all transports emit an "open" event — transports that do
/// not wait for an explicit open should skip calling this.
#[inline]
pub fn log_open_success(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
info!("transport open");
}
}
/// Log that opening the transport failed.
///
/// Useful for transports that report an explicit open failure to the
/// application. Transports that don't wait for opening can ignore this.
#[inline]
pub fn log_open_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("opening transport failed: {error}");
}
}
/// Helper method for logging readiness based on result.
///
/// See [log_ready_success](Logger::log_ready_success) and
/// [log_ready_failure](Logger::log_ready_failure) for more details.
#[inline]
pub fn log_ready<S, F>(&self, result: &Poll<Result<S, F>>)
where
F: std::error::Error,
{
match result {
Poll::Ready(Ok(_)) => self.log_ready_success(),
Poll::Ready(Err(error)) => self.log_ready_failure(error),
_ => {} // ignore
}
}
/// Log that the transport is ready for sending messages.
///
/// Currently this does not log anything to keep the log less verbose, but it may be changed in the future.
#[inline]
pub fn log_ready_success(&self) {
// ignore
}
/// Log that the transport failed to become ready for sending messages.
#[inline]
pub fn log_ready_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to become ready for sending: {error}");
}
}
/// Helper method for logging message staging based on result.
///
/// See [log_message_staging_success](Logger::log_message_staging_success) and
/// [log_message_staging_failure](Logger::log_message_staging_failure) for more
/// info.
#[inline]
pub fn log_message_staging<O, S, F>(&self, result: &Result<S, F>)
where
F: std::error::Error,
{
match result {
Ok(_) => {
self.log_message_staging_success::<O>();
}
Err(error) => self.log_message_staging_failure(error),
}
}
/// Log successful staging of an outgoing message for sending.
///
/// Used by transports that stage outgoing messages by putting them into buffer
/// before encoding and sending.
/// Not every transport stages messages before sending - this method may be unused.
#[inline]
pub fn log_message_staging_success<O>(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
trace!(
message_type = type_name::<O>(),
"staged message for sending"
);
}
}
/// Log failure while staging an outgoing message for sending.
///
/// Used by transports that stage outgoing messages by putting them into buffer
/// before encoding and sending.
/// Not every transport stages messages before sending - this method may be unused.
#[inline]
pub fn log_message_staging_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to stage message for sending: {error}");
}
}
/// Helper method for logging message preparation based on result.
///
/// See [log_message_preparation_success](Logger::log_message_preparation_success) and
/// [log_message_preparation_failure](Logger::log_message_preparation_failure) for more
/// info.
#[inline]
pub fn log_message_preparation<O, S, F>(
&self,
send_buffer_len_before: usize,
send_buffer_len_after: usize,
result: &Result<S, F>,
) where
F: std::error::Error,
{
match result {
Ok(_) => {
let message_size = send_buffer_len_after - send_buffer_len_before;
self.log_message_preparation_success::<O>(Some(message_size));
}
Err(error) => self.log_message_preparation_failure(error),
}
}
/// Log successful preparation of an outgoing message.
///
/// Used by transports that buffer or prepare messages before sending (flushing).
/// Not every transport buffers messages before sending.
#[inline]
pub fn log_message_preparation_success<O>(&self, size: Option<usize>) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
if let Some(size) = size {
trace!(
message_type = type_name::<O>(),
size_in_bytes = size,
"prepared message for sending"
);
} else {
trace!(
message_type = type_name::<O>(),
"prepared message for sending"
);
}
}
}
/// Log failure while preparing an outgoing message.
///
/// Used by buffered transports that perform message preparation steps
/// before sending (flushing); may be unused by simpler transports.
#[inline]
pub fn log_message_preparation_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to prepare message for sending: {error}");
}
}
/// Helper method for logging message sending based on result.
///
/// See [log_sending_success](Logger::log_sending_success) and
/// [log_sending_failure](Logger::log_sending_failure) for more
/// info.
#[inline]
pub fn log_sending<O, F>(&self, result: &Result<(), F>, size: Option<usize>)
where
F: std::error::Error,
{
match result {
Ok(_) => self.log_sending_success::<O>(size),
Err(error) => self.log_sending_failure(error),
}
}
/// Log that a message was sent successfully.
#[inline]
pub fn log_sending_success<O>(&self, size: Option<usize>) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
if let Some(size) = size {
debug!(
message_type = type_name::<O>(),
size_in_bytes = size,
"message sent"
);
} else {
debug!(message_type = type_name::<O>(), "message sent");
}
}
}
/// Log that sending a message failed.
#[inline]
pub fn log_sending_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to send message: {error}");
}
}
/// Log that a message data arrived (was received and enqueued).
///
/// This is used by transports that receive messages data in the background
/// and place them into a buffer for later deserialization and
/// consumption; not all transports will use arrival logs.
///
/// It is called "unknown" because at this point we don't know
/// if message deserialization will succeed or not.
#[inline]
pub fn log_message_arrived_unknown(&self, size: Option<usize>) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
if let Some(size) = size {
trace!(size_in_bytes = size, "new message arrived");
} else {
trace!("new message arrived");
}
}
}
/// Log that a message arrived (was received and enqueued).
///
/// This is used by transports that receive messages in the background
/// and place them into a buffer for later consumption; not all transports
/// will use arrival logs.
#[inline]
pub fn log_message_arrived_success<I>(&self, _item: &I, size: Option<usize>) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
if let Some(size) = size {
trace!(
message_type = type_name::<I>(),
size_in_bytes = size,
"new message arrived"
);
} else {
trace!(message_type = type_name::<I>(), "new message arrived");
}
}
}
/// Log failure during background arrival/enqueue of a received message.
///
/// Relevant for transports that buffer incoming messages in the background;
/// may be unused by transports that only receive message while precessing
/// `next` method.
#[inline]
pub fn log_message_arrived_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to process arriving message: {error}");
}
}
/// Helper method for logging receiving based on result.
///
/// See [log_receiving_success](Logger::log_receiving_success),
/// [log_receiving_failure](Logger::log_receiving_failure) and
/// [log_remote_closed](Logger::log_remote_closed) for more info.
#[inline]
pub fn log_receiving<I, F>(
&self,
result: &Poll<Option<Result<I, F>>>,
message_length: Option<usize>,
) where
F: std::error::Error,
{
match result {
Poll::Ready(Some(Ok(item))) => self.log_receiving_success(item, message_length),
Poll::Ready(Some(Err(error))) => self.log_receiving_failure(error),
Poll::Ready(None) => self.log_remote_closed(),
_ => {} // ignore
}
}
/// Log that a message was successfully received.
#[inline]
pub fn log_receiving_success<I>(&self, _item: &I, size: Option<usize>) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
if let Some(size) = size {
debug!(
message_type = type_name::<I>(),
size_in_bytes = size,
"received message"
);
} else {
debug!(message_type = type_name::<I>(), "received message");
}
}
}
/// Log that receiving a message failed.
#[inline]
pub fn log_receiving_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to receive message: {error}");
}
}
/// Log that an attempt to receive from a `Void` transport was made.
pub fn log_receive_from_void(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
warn!("attempted to receive from void");
}
}
/// Helper method for logging flush.
///
/// See [log_flush_success](Logger::log_flush_success) and
/// [log_flush_failure](Logger::log_flush_failure) for more
/// info.
#[inline]
pub fn log_flush<S, F>(&self, result: &Poll<Result<S, F>>)
where
F: std::error::Error,
{
match result {
Poll::Ready(Ok(_)) => self.log_flush_success(),
Poll::Ready(Err(error)) => self.log_flush_failure(error),
_ => {} // ignore
}
}
/// Log that buffered messages were flushed successfully.
#[inline]
pub fn log_flush_success(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
debug!("outgoing messages flushed");
}
}
/// Log that flushing buffered messages failed.
#[inline]
pub fn log_flush_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to flush outgoing messages: {error}");
}
}
/// Helper method for logging closing of the transport based on result.
///
/// See [log_closed_success](Logger::log_closed_success),
/// [log_closed_failure](Logger::log_closed_failure) for more info.
#[inline]
pub fn log_close<S, F>(&self, result: &Poll<Result<S, F>>)
where
F: std::error::Error,
{
match result {
Poll::Ready(Ok(_)) => self.log_closed_success(),
Poll::Ready(Err(error)) => self.log_closed_failure(error),
_ => {} // ignore
}
}
/// Log that the transport was closed locally successfully.
#[inline]
pub fn log_closed_success(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
info!("transport closed");
}
}
/// Log that closing the transport locally failed.
#[inline]
pub fn log_closed_failure(&self, error: impl std::error::Error) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
error!("failed to close transport: {error}");
}
}
/// Log that the remote peer closed the transport.
#[inline]
pub fn log_remote_closed(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
info!("remote transport closed");
}
}
/// Log that an incoming message was filtered out.
#[inline]
pub fn log_incoming_filtered_out<I>(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
trace!(
message_type = type_name::<I>(),
"incoming message filtered out"
);
}
}
/// Log that an outgoing message was filtered out.
#[inline]
pub fn log_outgoing_filtered_out<I>(&self) {
if self.enabled {
let span = self.span();
let _guard = span.enter();
trace!(
message_type = type_name::<I>(),
"outgoing message filtered out"
);
}
}
/// Set transport name for logging purposes.
pub fn set_transport_name(&mut self, name: Option<String>) {
self.name = name;
}
/// Get transport name for logging purposes.
pub fn get_transport_name(&self) -> Option<&str> {
self.name.as_deref()
}
/// Enable logging.
pub fn enable(&mut self) {
self.enabled = true;
}
/// Disable logging.
pub fn disable(&mut self) {
self.enabled = false;
}
/// Is logging enabled.
pub fn is_enabled(&self) -> bool {
self.enabled
}
/// Override existing logger kind with another transport type kind.
pub fn override_kind<T>(&mut self)
where
T: Logging,
{
self.kind = T::KIND.to_string();
}
/// Override existing logger kind with provided string.
pub fn override_kind_with_str(&mut self, kind: &str) {
self.kind = kind.to_string();
}
/// Override existing logger kind with another (buffered) transport type kind.
pub fn override_kind_buffered<T>(&mut self)
where
T: Logging,
{
self.kind = format!("{}(buffered)", T::KIND);
}
/// Override existing logger kind with another (part) transport type kind.
pub fn override_kind_part<T>(&mut self, variant: usize)
where
T: Logging,
{
self.kind = format!("{}({variant})", T::KIND);
}
/// Create a tracing span for this transport.
pub fn span(&self) -> Span {
if let Some(name) = &self.name {
trace_span!("dnet", transport = self.kind, name = name.as_str())
} else {
trace_span!("dnet", transport = self.kind)
}
}
}