Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Commit 8f25f76

Browse files
committed
Added a logging adapter from log crate logging to glib's
1 parent 7e9eee4 commit 8f25f76

File tree

5 files changed

+201
-7
lines changed

5 files changed

+201
-7
lines changed

.travis.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,25 @@ matrix:
77
env: GTK=3.14 FEATURES=
88
- os: linux
99
rust: nightly
10-
env: GTK=3.24 FEATURES=v2_48
10+
env: GTK=3.24 FEATURES="v2_48 log"
1111
- os: linux
1212
rust: beta
1313
env: GTK=3.14 FEATURES=
1414
- os: linux
1515
rust: beta
16-
env: GTK=3.24 FEATURES=v2_48
16+
env: GTK=3.24 FEATURES="v2_48 log"
1717
- os: linux
1818
rust: 1.40.0
1919
env: GTK=3.14 FEATURES=
2020
- os: linux
2121
rust: 1.40.0
22-
env: GTK=3.24 FEATURES=v2_48
22+
env: GTK=3.24 FEATURES="v2_48 log"
2323
- os: linux
2424
rust: stable
2525
env: GTK=3.14 FEATURES=
2626
- os: linux
2727
rust: stable
28-
env: GTK=3.24 FEATURES=v2_48
28+
env: GTK=3.24 FEATURES="v2_48 log"
2929
- os: osx
3030
rust: nightly
3131
env: GTK=3.14 FEATURES=
@@ -55,7 +55,7 @@ matrix:
5555
env: GTK=3.14 FEATURES= ARM=1 OTHER_TARGET="--target armv7-unknown-linux-gnueabihf"
5656
- os: linux
5757
rust: nightly
58-
env: GTK=3.24 FEATURES=v2_48 ARM=1 OTHER_TARGET="--target armv7-unknown-linux-gnueabihf"
58+
env: GTK=3.24 FEATURES="v2_48 log" ARM=1 OTHER_TARGET="--target armv7-unknown-linux-gnueabihf"
5959
addons:
6060
apt:
6161
packages:

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ futures-channel = "0.3"
3232
glib-sys = { git = "https://github.com/gtk-rs/sys" }
3333
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
3434
glib-macros = { path = "glib-macros" }
35+
log = { version = "0.4", optional = true }
3536

3637
[dev-dependencies]
3738
tempfile = "3"
@@ -48,7 +49,7 @@ v2_58 = ["v2_56", "glib-sys/v2_58", "gobject-sys/v2_58"]
4849
v2_60 = ["v2_58", "glib-sys/v2_60"]
4950
v2_62 = ["v2_60", "glib-sys/v2_62", "gobject-sys/v2_62"]
5051
v2_64 = ["v2_62", "glib-sys/v2_64"]
51-
dox = ["glib-sys/dox", "gobject-sys/dox"]
52+
dox = ["glib-sys/dox", "gobject-sys/dox", "log"]
5253

5354
[package.metadata.docs.rs]
5455
features = ["dox"]

src/bridged_logging.rs

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// Copyright 2020, The Gtk-rs Project Developers.
2+
// See the COPYRIGHT file at the top-level directory of this distribution.
3+
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4+
5+
extern crate log as rs_log;
6+
7+
use glib_sys;
8+
use translate::*;
9+
10+
/// Enumeration of the possible formatting behaviours for a
11+
/// [`GlibLogger`](struct.GlibLogger.html).
12+
///
13+
/// In order to use this type, `glib` must be built with the `log` feature
14+
/// enabled.
15+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16+
pub enum GlibLoggerFormat {
17+
/// A simple format, writing only the message on output.
18+
Plain,
19+
/// A simple format, writing file, line and message on output.
20+
LineAndFile,
21+
/// A logger using glib structured logging. Structured logging is available
22+
/// only on features `v2_56` and later.
23+
#[cfg(any(feature = "v2_56", feature = "dox"))]
24+
Structured,
25+
}
26+
27+
/// Enumeration of the possible domain handling behaviours for a
28+
/// [`GlibLogger`](struct.GlibLogger.html).
29+
///
30+
/// In order to use this type, `glib` must be built with the `log` feature
31+
/// enabled.
32+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33+
pub enum GlibLoggerDomain {
34+
/// Logs will have no domain specified.
35+
None,
36+
/// Logs will use the `target` of the log crate as a domain; this allows
37+
/// Rust code like `warn!(target: "my-domain", "...");` to log to the glib
38+
/// logger using the specified domain.
39+
CrateTarget,
40+
/// Logs will use the crate path as the log domain.
41+
CratePath,
42+
}
43+
44+
/// An implementation of a [`log`](https://crates.io/crates/log) compatible
45+
/// logger which logs over glib logging facilities.
46+
///
47+
/// In order to use this type, `glib` must be built with the `log` feature
48+
/// enabled.
49+
///
50+
/// Example:
51+
///
52+
/// ```no_run
53+
/// extern crate log;
54+
///
55+
/// static glib_logger: glib::GlibLogger = glib::GlibLogger::new(
56+
/// glib::GlibLoggerFormat::Plain,
57+
/// glib::GlibLoggerDomain::CrateTarget,
58+
/// );
59+
///
60+
/// log::set_logger(&glib_logger);
61+
/// log::set_max_level(log::LevelFilter::Debug);
62+
///
63+
/// log::info!("This line will get logged by glib");
64+
/// ```
65+
#[derive(Debug)]
66+
pub struct GlibLogger {
67+
format: GlibLoggerFormat,
68+
domain: GlibLoggerDomain,
69+
}
70+
71+
impl GlibLogger {
72+
/// Creates a new instance of [`GlibLogger`](struct.GlibLogger.html).
73+
///
74+
/// Example:
75+
///
76+
/// ```no_run
77+
/// extern crate log;
78+
///
79+
/// static glib_logger: glib::GlibLogger = glib::GlibLogger::new(
80+
/// glib::GlibLoggerFormat::Plain,
81+
/// glib::GlibLoggerDomain::CrateTarget,
82+
/// );
83+
///
84+
/// log::set_logger(&glib_logger);
85+
/// log::set_max_level(log::LevelFilter::Debug);
86+
///
87+
/// log::info!("This line will get logged by glib");
88+
/// ```
89+
pub const fn new(format: GlibLoggerFormat, domain: GlibLoggerDomain) -> Self {
90+
GlibLogger { format, domain }
91+
}
92+
93+
fn level_to_glib(level: rs_log::Level) -> glib_sys::GLogLevelFlags {
94+
match level {
95+
// Errors are mapped to critical to avoid automatic termination
96+
rs_log::Level::Error => glib_sys::G_LOG_LEVEL_CRITICAL,
97+
rs_log::Level::Warn => glib_sys::G_LOG_LEVEL_WARNING,
98+
rs_log::Level::Info => glib_sys::G_LOG_LEVEL_INFO,
99+
rs_log::Level::Debug => glib_sys::G_LOG_LEVEL_DEBUG,
100+
// There is no equivalent to trace level in glib
101+
rs_log::Level::Trace => glib_sys::G_LOG_LEVEL_DEBUG,
102+
}
103+
}
104+
105+
fn write_log(domain: Option<&str>, level: rs_log::Level, message: &str) {
106+
unsafe {
107+
crate::glib_sys::g_log(
108+
domain.to_glib_none().0,
109+
GlibLogger::level_to_glib(level),
110+
message.replace("%", "%%").to_glib_none().0,
111+
);
112+
}
113+
}
114+
115+
#[cfg(any(feature = "v2_56", feature = "dox"))]
116+
fn write_log_structured(
117+
domain: Option<&str>,
118+
level: log::Level,
119+
file: Option<&str>,
120+
line: Option<u32>,
121+
func: Option<&str>,
122+
message: &str,
123+
) {
124+
let line_str = match line {
125+
None => None,
126+
Some(l) => Some(l.to_string()),
127+
};
128+
129+
unsafe {
130+
crate::glib_sys::g_log_structured_standard(
131+
domain.to_glib_none().0,
132+
GlibLogger::level_to_glib(level),
133+
file.to_glib_none().0,
134+
line_str.to_glib_none().0,
135+
func.to_glib_none().0,
136+
message.replace("%", "%%").to_glib_none().0,
137+
);
138+
}
139+
}
140+
}
141+
142+
impl rs_log::Log for GlibLogger {
143+
fn enabled(&self, _: &rs_log::Metadata) -> bool {
144+
true
145+
}
146+
147+
fn log(&self, record: &rs_log::Record) {
148+
if !self.enabled(record.metadata()) {
149+
return;
150+
}
151+
152+
let domain = match &self.domain {
153+
GlibLoggerDomain::None => None,
154+
GlibLoggerDomain::CrateTarget => Some(record.metadata().target()),
155+
GlibLoggerDomain::CratePath => record.module_path(),
156+
};
157+
158+
match self.format {
159+
GlibLoggerFormat::Plain => {
160+
let s = format!("{}", record.args());
161+
GlibLogger::write_log(domain, record.level(), &s)
162+
}
163+
GlibLoggerFormat::LineAndFile => {
164+
let s = match (record.file(), record.line()) {
165+
(Some(file), Some(line)) => format!("{}:{}: {}", file, line, record.args()),
166+
(Some(file), None) => format!("{}: {}", file, record.args()),
167+
_ => format!("{}", record.args()),
168+
};
169+
170+
GlibLogger::write_log(domain, record.level(), &s);
171+
}
172+
#[cfg(any(feature = "v2_56", feature = "dox"))]
173+
GlibLoggerFormat::Structured => {
174+
GlibLogger::write_log_structured(
175+
domain,
176+
record.level(),
177+
record.file(),
178+
record.line(),
179+
None,
180+
&format!("{}", record.args()),
181+
);
182+
}
183+
};
184+
}
185+
186+
fn flush(&self) {}
187+
}

src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ pub use quark::Quark;
190190
mod log;
191191
#[cfg(any(feature = "v2_46", feature = "dox"))]
192192
pub use log::log_set_handler;
193+
193194
// #[cfg(any(feature = "v2_50", feature = "dox"))]
194195
// pub use log::log_variant;
195196
pub use log::{
@@ -198,6 +199,11 @@ pub use log::{
198199
unset_print_handler, unset_printerr_handler, LogHandlerId, LogLevel, LogLevels,
199200
};
200201

202+
#[cfg(any(feature = "log", feature = "dox"))]
203+
mod bridged_logging;
204+
#[cfg(any(feature = "log", feature = "dox"))]
205+
pub use bridged_logging::{GlibLogger, GlibLoggerDomain, GlibLoggerFormat};
206+
201207
pub mod send_unique;
202208
pub use send_unique::{SendUnique, SendUniqueCell};
203209

src/source_futures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,8 +373,8 @@ pub fn unix_signal_stream_with_priority(
373373
#[cfg(test)]
374374
mod tests {
375375
use super::*;
376-
use std::time::Duration;
377376
use std::thread;
377+
use std::time::Duration;
378378

379379
#[test]
380380
fn test_timeout() {

0 commit comments

Comments
 (0)