Skip to content

Commit 7c111f9

Browse files
committed
tests
Signed-off-by: tison <[email protected]>
1 parent 49c2d11 commit 7c111f9

File tree

7 files changed

+179
-7
lines changed

7 files changed

+179
-7
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ jobs:
8989
cargo run --features="starter-log" --example json_stdout
9090
cargo run --features="starter-log" --example rolling_file
9191
cargo run --features="starter-log" --example single_file
92+
cargo run --features="starter-log,append-async" --example asynchronous
9293
cargo run --features="starter-log,diagnostic-fastrace,layout-google-cloud-logging" --example google_cloud_logging
9394
cargo run --features="starter-log,append-fastrace,diagnostic-fastrace" --example fastrace
9495

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/Cargo.lock
22
/target
3+
/logs

appenders/fastrace/src/lib.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,6 @@ impl Append for FastraceEvent {
8181
}
8282
}
8383

84-
impl Drop for FastraceEvent {
85-
fn drop(&mut self) {
86-
fastrace::flush();
87-
}
88-
}
89-
9084
struct KvCollector {
9185
kv: Vec<(String, String)>,
9286
}

logforth/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ serde = { workspace = true }
8787
[lints]
8888
workspace = true
8989

90+
[[test]]
91+
name = "global_async_sink"
92+
harness = false
93+
required-features = ["starter-log", "append-async"]
94+
95+
[[example]]
96+
doc-scrape-examples = true
97+
name = "asynchronous"
98+
path = "examples/asynchronous.rs"
99+
required-features = ["starter-log", "append-async"]
100+
90101
[[example]]
91102
doc-scrape-examples = true
92103
name = "testing"

logforth/examples/asynchronous.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2024 FastLabs Developers
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//! An example of logging to a single file with async combinator.
16+
17+
use logforth::append::file::FileBuilder;
18+
use logforth::layout::JsonLayout;
19+
use logforth::record::LevelFilter;
20+
use logforth_append_async::AsyncBuilder;
21+
22+
fn main() {
23+
let file = FileBuilder::new("logs", "my_app_async")
24+
.filename_suffix("log")
25+
.layout(JsonLayout::default())
26+
.build()
27+
.unwrap();
28+
29+
let asynchronous = AsyncBuilder::new("logforth-async").append(file).build();
30+
31+
logforth::starter_log::builder()
32+
.dispatch(|d| d.filter(LevelFilter::Trace).append(asynchronous))
33+
.apply();
34+
35+
log::error!("Hello single error!");
36+
log::warn!("Hello single warn!");
37+
log::info!("Hello single info!");
38+
log::debug!("Hello single debug!");
39+
log::trace!("Hello single trace!");
40+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright 2024 FastLabs Developers
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//! This case ensures that the asynchronous logger flushes correctly at program exit.
16+
17+
// This refers to https://github.com/SpriteOvO/spdlog-rs/issues/64
18+
19+
use std::fmt::Write;
20+
use std::os::raw::c_int;
21+
use std::sync::atomic::AtomicBool;
22+
use std::sync::atomic::Ordering;
23+
24+
use logforth_append_async::AsyncBuilder;
25+
use logforth_core::Append;
26+
use logforth_core::Diagnostic;
27+
use logforth_core::Error;
28+
use logforth_core::record::LevelFilter;
29+
use logforth_core::record::Record;
30+
31+
static IS_LOGGED: AtomicBool = AtomicBool::new(false);
32+
static IS_FLUSHED: AtomicBool = AtomicBool::new(false);
33+
34+
#[derive(Debug)]
35+
struct SetFlags;
36+
37+
impl Append for SetFlags {
38+
fn append(&self, _: &Record, _: &[Box<dyn Diagnostic>]) -> Result<(), Error> {
39+
IS_LOGGED.store(true, Ordering::SeqCst);
40+
Ok(())
41+
}
42+
43+
fn flush(&self) -> Result<(), Error> {
44+
// assert that the record has been logged before flushing
45+
assert!(IS_LOGGED.load(Ordering::SeqCst));
46+
IS_FLUSHED.store(true, Ordering::SeqCst);
47+
Ok(())
48+
}
49+
}
50+
51+
fn run_test() {
52+
{
53+
extern "C" fn check() {
54+
// assert that `Async` appender in the default logger will be flushed correctly
55+
// and will not panic.
56+
assert!(IS_FLUSHED.load(Ordering::SeqCst));
57+
}
58+
59+
// set up `atexit` to check the flag at the end of the program
60+
unsafe extern "C" {
61+
fn atexit(cb: extern "C" fn()) -> c_int;
62+
}
63+
64+
assert_eq!(unsafe { atexit(check) }, 0);
65+
66+
let asynchronous = AsyncBuilder::new("async-appender").append(SetFlags).build();
67+
68+
logforth::starter_log::builder()
69+
.dispatch(|d| d.filter(LevelFilter::Trace).append(asynchronous))
70+
.apply();
71+
}
72+
73+
log::info!("hello async sink");
74+
}
75+
76+
fn main() {
77+
// This is a flaky test, it only has a certain probability of failing,
78+
// so we run it multiple times to make sure it's really working properly.
79+
{
80+
let mut captured_output = String::new();
81+
let args = std::env::args().collect::<Vec<_>>();
82+
83+
let is_parent = args.iter().all(|arg| arg != "child");
84+
if is_parent {
85+
for i in 0..1000 {
86+
let output = std::process::Command::new(&args[0])
87+
.arg("child")
88+
.stderr(std::process::Stdio::piped())
89+
.output()
90+
.unwrap();
91+
92+
let success = output.status.success();
93+
writeln!(
94+
captured_output,
95+
"Attempt #{i} = {}",
96+
if success { "ok" } else { "failed!" }
97+
)
98+
.unwrap();
99+
100+
if !success {
101+
eprintln!("{captured_output}");
102+
103+
let stderr = String::from_utf8_lossy(&output.stderr).lines().fold(
104+
String::new(),
105+
|mut contents, line| {
106+
writeln!(&mut contents, "> {line}").unwrap();
107+
contents
108+
},
109+
);
110+
111+
eprintln!("stderr of the failed attempt:\n{stderr}");
112+
panic!("test failed");
113+
}
114+
}
115+
return;
116+
} else {
117+
assert_eq!(args[1], "child");
118+
}
119+
}
120+
121+
// Run the test after leaving the scope, so the main function ends
122+
// without dropping additional variables, thus exiting faster. This
123+
// should increase the probability of reproducing the error.
124+
run_test();
125+
}

logforth/tests/recursive_logging.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
//! This case ensures our impl does properly handle recursive logging.
1616
17-
#![cfg(feature = "append-file")]
17+
#![cfg(feature = "starter-log")]
1818

1919
use std::num::NonZeroUsize;
2020

0 commit comments

Comments
 (0)