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
// This file is part of dpdk. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/dpdk/master/COPYRIGHT. No part of dpdk, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
// Copyright © 2016-2019 The developers of dpdk. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/dpdk/master/COPYRIGHT.


/// Logging configuration.
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[derive(Serialize, Deserialize)]
#[serde(default)]
pub struct LoggingConfiguration
{
	/// Defaults to `auth`.
	pub syslog_facility: SyslogFacility,
	
	/// Defaults to `debug` for debug builds and `warning` for production builds.
	///
	/// DPDK also supports specifying either a regex or a pattern; this is not supported by `LoggingConfiguration` at this time.
	pub syslog_priority: SyslogPriority,

	/// Up to 31 bytes (more are ignored) identifying the source of log messages.
	///
	/// Defaults to program name.
	pub identity: String,

	/// When a panic occurs that isn't caught (or if the error-chain crate is in use), capture a full stack back trace.
	pub enable_full_rust_stack_back_traces: bool,
}

impl Default for LoggingConfiguration
{
	#[inline(always)]
	fn default() -> Self
	{
		Self
		{
			syslog_facility: Default::default(),
			syslog_priority: Default::default(),
			identity: get_program_name(),
			enable_full_rust_stack_back_traces: true,
		}
	}
}

impl LoggingConfiguration
{
	/// Issues a warning (currently to syslog).
	#[inline(always)]
	pub fn warn(name: &str, message: String)
	{
		let name = to_c_string_robustly(name);
		let message = to_c_string_robustly(message);
		unsafe { syslog(LOG_WARNING, b"%s:%s\0".as_ptr() as *const _ as *const _, name.as_ptr(), message.as_ptr()) };
	}
	
	#[inline(always)]
	fn caught_panic(source_file: &str, line_number: u32, column_number: u32, cause: &str)
	{
		let source_file = to_c_string_robustly(source_file);
		let cause = to_c_string_robustly(cause);
		unsafe { syslog(LOG_CRIT, b"File:%s:Line:%u:Column:%u:Cause:%s\0".as_ptr() as *const _ as *const _, source_file, line_number, column_number, cause) }
	}

	/// Start logging.
	#[inline(always)]
	pub fn start_logging(&self, running_interactively: bool)
	{
		self.configure_rust_stack_back_traces();
		self.configure_syslog(running_interactively);
		self.configure_panic_hook()
	}

	/// Stop logging.
	#[inline(always)]
	pub fn stop_logging(&self)
	{
		drop(take_hook());
		unsafe { closelog() }
	}

	#[inline(always)]
	fn configure_rust_stack_back_traces(&self)
	{
		let setting = if self.enable_full_rust_stack_back_traces
		{
			"1"
		}
		else
		{
			"0"
		};
		set_var("RUST_BACKTRACE", setting);
	}

	#[inline(always)]
	fn configure_syslog(&self, running_interactively_so_also_log_to_standard_error: bool)
	{
		unsafe { setlogmask(self.syslog_priority.log_upto()) };
		
		let mut log_options = LOG_PID | LOG_NDELAY;
		
		if running_interactively_so_also_log_to_standard_error
		{
			log_options |= LOG_PERROR;
		}
		
		let identity = CString::new(self.identity.as_str()).unwrap();
		unsafe { openlog(identity.as_ptr(), log_options, self.syslog_facility as i32) }
	}

	#[inline(always)]
	fn configure_panic_hook(&self)
	{
		set_hook(Box::new(|panic_info|
		{
			let (source_file, line_number, column_number) = match panic_info.location()
			{
				None => ("(unknown source file)", 0, 0),
				Some(location) => (location.file(), location.line(), location.column())
			};
			
			let cause = panic_payload_to_cause(panic_info.payload());
			
			Self::caught_panic(source_file, line_number, column_number, &cause)
		}));
	}
}