Coverage Report

Created: 2026-03-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/log.rs
Line
Count
Source
1
/* Copyright (C) 2017 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
//! Logging utility module.
19
20
use std;
21
use std::ffi::CString;
22
use std::path::Path;
23
24
use crate::core::*;
25
26
#[derive(Debug)]
27
#[repr(C)]
28
pub enum Level {
29
    NotSet = -1,
30
    _None = 0,
31
    Error,
32
    Warning,
33
    Notice,
34
    Info,
35
    _Perf,
36
    Config,
37
    #[cfg(feature = "debug")]
38
    Debug,
39
}
40
41
pub static mut LEVEL: i32 = Level::NotSet as i32;
42
43
73.4k
pub fn get_log_level() -> i32 {
44
    unsafe {
45
73.4k
        LEVEL
46
    }
47
73.4k
}
48
49
37
pub fn log_set_level(level: i32) {
50
37
    unsafe {
51
37
        LEVEL = level;
52
37
    }
53
37
}
54
55
#[no_mangle]
56
37
pub extern "C" fn rs_log_set_level(level: i32) {
57
37
    log_set_level(level);
58
37
}
59
60
73.3k
fn basename(filename: &str) -> &str {
61
73.3k
    let path = Path::new(filename);
62
73.3k
    if let Some(os_str) = path.file_name() {
63
73.3k
        if let Some(basename) = os_str.to_str() {
64
73.3k
            return basename;
65
0
        }
66
0
    }
67
0
    return filename;
68
73.3k
}
69
70
73.3k
pub fn sclog(level: Level, file: &str, line: u32, function: &str,
71
73.3k
         message: &str)
72
{
73
73.3k
    let filename = basename(file);
74
73.3k
    let noext = &filename[0..filename.len() - 3];
75
73.3k
    sc_log_message(level,
76
73.3k
                   filename,
77
73.3k
                   line,
78
73.3k
                   function,
79
73.3k
                   noext,
80
73.3k
                   message);
81
73.3k
}
82
83
// This macro returns the function name.
84
//
85
// This macro has been borrowed from https://github.com/popzxc/stdext-rs, which
86
// is released under the MIT license as there is currently no macro in Rust
87
// to provide the function name.
88
#[macro_export(local_inner_macros)]
89
macro_rules!function {
90
    () => {{
91
         // Okay, this is ugly, I get it. However, this is the best we can get on a stable rust.
92
0
         fn __f() {}
Unexecuted instantiation: <suricata::applayertemplate::template::TemplateState>::parse_request::__f
Unexecuted instantiation: <suricata::applayertemplate::template::TemplateState>::parse_response::__f
Unexecuted instantiation: <suricata::applayertemplate::template::TemplateState>::parse_response::__f
Unexecuted instantiation: <suricata::applayertemplate::template::TemplateState>::parse_response::__f
Unexecuted instantiation: suricata::applayertemplate::template::rs_template_register_parser::__f
Unexecuted instantiation: suricata::applayertemplate::template::rs_template_register_parser::__f
Unexecuted instantiation: suricata::applayertemplate::template::rs_template_register_parser::__f
Unexecuted instantiation: suricata::nfs::nfs::rs_nfs_udp_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::__f
Unexecuted instantiation: suricata::ssh::ssh::rs_ssh_register_parser::__f
Unexecuted instantiation: suricata::asn1::parse_rules::rs_detect_asn1_parse::__f
Unexecuted instantiation: suricata::asn1::parse_rules::rs_detect_asn1_parse::__f
Unexecuted instantiation: suricata::mqtt::mqtt::rs_mqtt_register_parser::__f
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::__f
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::__f
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::__f
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::__f
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::__f
Unexecuted instantiation: suricata::pgsql::pgsql::SCRegisterPgsqlParser::__f
Unexecuted instantiation: suricata::pgsql::pgsql::SCRegisterPgsqlParser::__f
Unexecuted instantiation: suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::__f
Unexecuted instantiation: suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::__f
Unexecuted instantiation: suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::__f
Unexecuted instantiation: suricata::detect::requires::parse_requires::__f
Unexecuted instantiation: suricata::detect::requires::SCDetectRequiresStatusLog::__f
Unexecuted instantiation: suricata::detect::requires::SCDetectRequiresStatusLog::__f
Unexecuted instantiation: suricata::modbus::detect::parse_range::__f
Unexecuted instantiation: suricata::modbus::detect::parse_range::__f
Unexecuted instantiation: suricata::modbus::detect::parse_range::__f
Unexecuted instantiation: suricata::modbus::detect::parse_access::__f
Unexecuted instantiation: suricata::modbus::detect::parse_access::__f
Unexecuted instantiation: suricata::modbus::detect::parse_access::__f
Unexecuted instantiation: suricata::modbus::detect::parse_access::__f
Unexecuted instantiation: suricata::modbus::detect::parse_access::__f
Unexecuted instantiation: suricata::modbus::detect::parse_access::__f
Unexecuted instantiation: suricata::modbus::detect::parse_access::__f
Unexecuted instantiation: suricata::modbus::detect::parse_unit_id::__f
Unexecuted instantiation: suricata::modbus::detect::parse_unit_id::__f
Unexecuted instantiation: suricata::modbus::detect::parse_function::__f
Unexecuted instantiation: suricata::modbus::detect::parse_function::__f
Unexecuted instantiation: suricata::modbus::detect::parse_function::__f
93
73.3k
         fn type_name_of<T>(_: T) -> &'static str {
94
73.3k
             std::any::type_name::<T>()
95
73.3k
         }
suricata::modbus::detect::parse_range::type_name_of::<suricata::modbus::detect::parse_range::__f>
Line
Count
Source
93
469
         fn type_name_of<T>(_: T) -> &'static str {
94
469
             std::any::type_name::<T>()
95
469
         }
suricata::modbus::detect::parse_range::type_name_of::<suricata::modbus::detect::parse_range::__f>
Line
Count
Source
93
10
         fn type_name_of<T>(_: T) -> &'static str {
94
10
             std::any::type_name::<T>()
95
10
         }
suricata::modbus::detect::parse_range::type_name_of::<suricata::modbus::detect::parse_range::__f>
Line
Count
Source
93
24
         fn type_name_of<T>(_: T) -> &'static str {
94
24
             std::any::type_name::<T>()
95
24
         }
Unexecuted instantiation: suricata::modbus::detect::parse_access::type_name_of::<suricata::modbus::detect::parse_access::__f>
Unexecuted instantiation: suricata::modbus::detect::parse_access::type_name_of::<suricata::modbus::detect::parse_access::__f>
Unexecuted instantiation: suricata::modbus::detect::parse_access::type_name_of::<suricata::modbus::detect::parse_access::__f>
Unexecuted instantiation: suricata::modbus::detect::parse_access::type_name_of::<suricata::modbus::detect::parse_access::__f>
Unexecuted instantiation: suricata::modbus::detect::parse_access::type_name_of::<suricata::modbus::detect::parse_access::__f>
Unexecuted instantiation: suricata::modbus::detect::parse_access::type_name_of::<suricata::modbus::detect::parse_access::__f>
Unexecuted instantiation: suricata::modbus::detect::parse_access::type_name_of::<suricata::modbus::detect::parse_access::__f>
suricata::modbus::detect::parse_unit_id::type_name_of::<suricata::modbus::detect::parse_unit_id::__f>
Line
Count
Source
93
1.97k
         fn type_name_of<T>(_: T) -> &'static str {
94
1.97k
             std::any::type_name::<T>()
95
1.97k
         }
Unexecuted instantiation: suricata::modbus::detect::parse_unit_id::type_name_of::<suricata::modbus::detect::parse_unit_id::__f>
suricata::modbus::detect::parse_function::type_name_of::<suricata::modbus::detect::parse_function::__f>
Line
Count
Source
93
455
         fn type_name_of<T>(_: T) -> &'static str {
94
455
             std::any::type_name::<T>()
95
455
         }
suricata::modbus::detect::parse_function::type_name_of::<suricata::modbus::detect::parse_function::__f>
Line
Count
Source
93
1.62k
         fn type_name_of<T>(_: T) -> &'static str {
94
1.62k
             std::any::type_name::<T>()
95
1.62k
         }
Unexecuted instantiation: suricata::modbus::detect::parse_function::type_name_of::<suricata::modbus::detect::parse_function::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::smb::smb::rs_smb_register_parser::type_name_of::<suricata::smb::smb::rs_smb_register_parser::__f>
Unexecuted instantiation: suricata::ssh::ssh::rs_ssh_register_parser::type_name_of::<suricata::ssh::ssh::rs_ssh_register_parser::__f>
Unexecuted instantiation: suricata::mqtt::mqtt::rs_mqtt_register_parser::type_name_of::<suricata::mqtt::mqtt::rs_mqtt_register_parser::__f>
Unexecuted instantiation: suricata::asn1::parse_rules::rs_detect_asn1_parse::type_name_of::<suricata::asn1::parse_rules::rs_detect_asn1_parse::__f>
suricata::asn1::parse_rules::rs_detect_asn1_parse::type_name_of::<suricata::asn1::parse_rules::rs_detect_asn1_parse::__f>
Line
Count
Source
93
1.20k
         fn type_name_of<T>(_: T) -> &'static str {
94
1.20k
             std::any::type_name::<T>()
95
1.20k
         }
suricata::detect::requires::parse_requires::type_name_of::<suricata::detect::requires::parse_requires::__f>
Line
Count
Source
93
39.5k
         fn type_name_of<T>(_: T) -> &'static str {
94
39.5k
             std::any::type_name::<T>()
95
39.5k
         }
suricata::detect::requires::SCDetectRequiresStatusLog::type_name_of::<suricata::detect::requires::SCDetectRequiresStatusLog::__f>
Line
Count
Source
93
83
         fn type_name_of<T>(_: T) -> &'static str {
94
83
             std::any::type_name::<T>()
95
83
         }
suricata::detect::requires::SCDetectRequiresStatusLog::type_name_of::<suricata::detect::requires::SCDetectRequiresStatusLog::__f>
Line
Count
Source
93
37
         fn type_name_of<T>(_: T) -> &'static str {
94
37
             std::any::type_name::<T>()
95
37
         }
<suricata::applayertemplate::template::TemplateState>::parse_request::type_name_of::<<suricata::applayertemplate::template::TemplateState>::parse_request::__f>
Line
Count
Source
93
9.52k
         fn type_name_of<T>(_: T) -> &'static str {
94
9.52k
             std::any::type_name::<T>()
95
9.52k
         }
<suricata::applayertemplate::template::TemplateState>::parse_response::type_name_of::<<suricata::applayertemplate::template::TemplateState>::parse_response::__f>
Line
Count
Source
93
6.10k
         fn type_name_of<T>(_: T) -> &'static str {
94
6.10k
             std::any::type_name::<T>()
95
6.10k
         }
<suricata::applayertemplate::template::TemplateState>::parse_response::type_name_of::<<suricata::applayertemplate::template::TemplateState>::parse_response::__f>
Line
Count
Source
93
6.10k
         fn type_name_of<T>(_: T) -> &'static str {
94
6.10k
             std::any::type_name::<T>()
95
6.10k
         }
<suricata::applayertemplate::template::TemplateState>::parse_response::type_name_of::<<suricata::applayertemplate::template::TemplateState>::parse_response::__f>
Line
Count
Source
93
6.10k
         fn type_name_of<T>(_: T) -> &'static str {
94
6.10k
             std::any::type_name::<T>()
95
6.10k
         }
Unexecuted instantiation: suricata::applayertemplate::template::rs_template_register_parser::type_name_of::<suricata::applayertemplate::template::rs_template_register_parser::__f>
Unexecuted instantiation: suricata::applayertemplate::template::rs_template_register_parser::type_name_of::<suricata::applayertemplate::template::rs_template_register_parser::__f>
suricata::applayertemplate::template::rs_template_register_parser::type_name_of::<suricata::applayertemplate::template::rs_template_register_parser::__f>
Line
Count
Source
93
33
         fn type_name_of<T>(_: T) -> &'static str {
94
33
             std::any::type_name::<T>()
95
33
         }
Unexecuted instantiation: suricata::nfs::nfs::rs_nfs_udp_register_parser::type_name_of::<suricata::nfs::nfs::rs_nfs_udp_register_parser::__f>
Unexecuted instantiation: suricata::pgsql::pgsql::SCRegisterPgsqlParser::type_name_of::<suricata::pgsql::pgsql::SCRegisterPgsqlParser::__f>
Unexecuted instantiation: suricata::pgsql::pgsql::SCRegisterPgsqlParser::type_name_of::<suricata::pgsql::pgsql::SCRegisterPgsqlParser::__f>
Unexecuted instantiation: suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::type_name_of::<suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::__f>
Unexecuted instantiation: suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::type_name_of::<suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::__f>
Unexecuted instantiation: suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::type_name_of::<suricata::dcerpc::dcerpc::rs_dcerpc_register_parser::__f>
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::type_name_of::<suricata::http2::http2::rs_http2_register_parser::__f>
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::type_name_of::<suricata::http2::http2::rs_http2_register_parser::__f>
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::type_name_of::<suricata::http2::http2::rs_http2_register_parser::__f>
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::type_name_of::<suricata::http2::http2::rs_http2_register_parser::__f>
Unexecuted instantiation: suricata::http2::http2::rs_http2_register_parser::type_name_of::<suricata::http2::http2::rs_http2_register_parser::__f>
96
         let name = type_name_of(__f);
97
         &name[..name.len() - 5]
98
    }}
99
}
100
101
#[macro_export]
102
macro_rules!do_log {
103
    ($level:expr, $($arg:tt)*) => {
104
        if $crate::log::get_log_level() >= $level as i32 {
105
            $crate::log::sclog($level, file!(), line!(), $crate::function!(),
106
                  &(format!($($arg)*)));
107
        }
108
    }
109
}
110
111
#[macro_export]
112
macro_rules!SCLogError {
113
    ($($arg:tt)*) => {
114
        $crate::do_log!($crate::log::Level::Error, $($arg)*);
115
    };
116
}
117
118
#[macro_export]
119
macro_rules!SCLogWarning {
120
    ($($arg:tt)*) => {
121
        $crate::do_log!($crate::log::Level::Warning, $($arg)*);
122
    };
123
}
124
125
#[macro_export]
126
macro_rules!SCLogNotice {
127
    ($($arg:tt)*) => {
128
        $crate::do_log!($crate::log::Level::Notice, $($arg)*);
129
    }
130
}
131
132
#[macro_export]
133
macro_rules!SCLogInfo {
134
    ($($arg:tt)*) => {
135
        $crate::do_log!($crate::log::Level::Info, $($arg)*);
136
    }
137
}
138
139
#[macro_export]
140
macro_rules!SCLogPerf {
141
    ($($arg:tt)*) => {
142
        $crate::do_log!($crate::log::Level::Perf, $($arg)*);
143
    }
144
}
145
146
#[macro_export]
147
macro_rules!SCLogConfig {
148
    ($($arg:tt)*) => {
149
        $crate::do_log!($crate::log::Level::Config, $($arg)*);
150
    }
151
}
152
153
// Debug mode: call C SCLogDebug
154
#[cfg(feature = "debug")]
155
#[macro_export]
156
macro_rules!SCLogDebug {
157
    ($($arg:tt)*) => {
158
        do_log!($crate::log::Level::Debug, $($arg)*);
159
    }
160
}
161
162
// SCLogDebug variation to use when not compiled with debug support.
163
//
164
// This macro will only use the parameters passed to prevent warnings
165
// about unused variables, but is otherwise the equivalent to a no-op.
166
#[cfg(not(feature = "debug"))]
167
#[macro_export]
168
macro_rules!SCLogDebug {
169
    ($($arg:tt)*) => ()
170
}
171
172
/// SCLogMessage wrapper. If the Suricata C context is not registered
173
/// a more basic log format will be used (for example, when running
174
/// Rust unit tests).
175
73.3k
pub fn sc_log_message(level: Level,
176
73.3k
                      filename: &str,
177
73.3k
                      line: std::os::raw::c_uint,
178
73.3k
                      function: &str,
179
73.3k
                      module: &str,
180
73.3k
                      message: &str) -> std::os::raw::c_int
181
{
182
    unsafe {
183
73.3k
        if let Some(c) = SC {
184
73.3k
            return (c.SCLogMessage)(
185
73.3k
                level as i32,
186
73.3k
                to_safe_cstring(filename).as_ptr(),
187
73.3k
                line,
188
73.3k
                to_safe_cstring(function).as_ptr(),
189
73.3k
                to_safe_cstring(module).as_ptr(),
190
73.3k
                to_safe_cstring(message).as_ptr());
191
0
        }
192
    }
193
194
    // Fall back if the Suricata C context is not registered which is
195
    // the case when Rust unit tests are running.
196
    //
197
    // We don't log the time right now as I don't think it can be done
198
    // with Rust 1.7.0 without using an external crate. With Rust
199
    // 1.8.0 and newer we can unix UNIX_EPOCH.elapsed() to get the
200
    // unix time.
201
0
    println!("{}:{} <{:?}> -- {}", filename, line, level, message);
202
0
    return 0;
203
73.3k
}
204
205
// Convert a &str into a CString by first stripping NUL bytes.
206
293k
fn to_safe_cstring(val: &str) -> CString {
207
293k
    let mut safe = Vec::with_capacity(val.len());
208
8.26M
    for c in val.as_bytes() {
209
8.26M
        if *c != 0 {
210
8.26M
            safe.push(*c);
211
8.26M
        }
212
    }
213
293k
    match CString::new(safe) {
214
293k
        Ok(cstr) => cstr,
215
        _ => {
216
0
            CString::new("<failed to encode string>").unwrap()
217
        }
218
    }
219
293k
}