Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/rust/src/logger.rs
2885 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
use crate::config::{BooleanKey, StringKey};
19
use crate::metadata::now_unix_timestamp;
20
21
use env_logger::Target::{Stderr, Stdout};
22
use env_logger::DEFAULT_FILTER_ENV;
23
use log::LevelFilter::{Debug, Info, Trace};
24
use log::{Level, LevelFilter};
25
use serde::{Deserialize, Serialize};
26
use std::cell::RefCell;
27
use std::env;
28
use std::fmt::Display;
29
use std::str::FromStr;
30
31
pub const DRIVER_PATH: &str = "Driver path: ";
32
pub const BROWSER_PATH: &str = "Browser path: ";
33
34
#[derive(Default, PartialEq)]
35
enum OutputType {
36
#[default]
37
Logger,
38
Json,
39
Shell,
40
Mixed,
41
}
42
43
#[derive(Default)]
44
pub struct Logger {
45
debug: bool,
46
trace: bool,
47
output: OutputType,
48
json: RefCell<JsonOutput>,
49
minimal_json: RefCell<MinimalJson>,
50
}
51
52
#[derive(Default, Serialize, Deserialize)]
53
pub struct Logs {
54
pub level: String,
55
pub timestamp: u64,
56
pub message: String,
57
}
58
59
#[derive(Default, Serialize, Deserialize)]
60
pub struct Result {
61
pub code: i32,
62
pub message: String,
63
pub driver_path: String,
64
pub browser_path: String,
65
}
66
67
#[derive(Default, Serialize, Deserialize)]
68
pub struct JsonOutput {
69
pub logs: Vec<Logs>,
70
pub result: Result,
71
}
72
73
#[derive(Default, Serialize, Deserialize)]
74
pub struct MinimalJson {
75
pub driver_path: String,
76
pub browser_path: String,
77
pub error: String,
78
}
79
80
impl Logger {
81
pub fn new() -> Self {
82
let debug = BooleanKey("debug", false).get_value();
83
let trace = BooleanKey("trace", false).get_value();
84
let log_level = StringKey(vec!["log-level"], "").get_value();
85
Logger::create("", debug, trace, &log_level)
86
}
87
88
pub fn create(output: &str, debug: bool, trace: bool, log_level: &str) -> Self {
89
let output_type;
90
if output.eq_ignore_ascii_case("json") {
91
output_type = OutputType::Json;
92
} else if output.eq_ignore_ascii_case("shell") {
93
output_type = OutputType::Shell;
94
} else if output.eq_ignore_ascii_case("mixed") {
95
output_type = OutputType::Mixed;
96
} else {
97
output_type = OutputType::Logger;
98
}
99
match output_type {
100
OutputType::Logger | OutputType::Mixed => {
101
if env::var(DEFAULT_FILTER_ENV).unwrap_or_default().is_empty() {
102
let mut filter = if !log_level.is_empty() {
103
LevelFilter::from_str(log_level).unwrap_or(Info)
104
} else {
105
let mut filter = match debug {
106
true => Debug,
107
false => Info,
108
};
109
if trace {
110
filter = Trace;
111
}
112
filter
113
};
114
if trace {
115
filter = Trace
116
}
117
let target = if output_type == OutputType::Logger {
118
Stdout
119
} else {
120
Stderr
121
};
122
env_logger::Builder::new()
123
.filter_module(env!("CARGO_CRATE_NAME"), filter)
124
.target(target)
125
.format_target(false)
126
.format_timestamp_millis()
127
.try_init()
128
.unwrap_or_default();
129
} else {
130
env_logger::try_init().unwrap_or_default();
131
}
132
}
133
_ => {
134
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info"))
135
.try_init()
136
.unwrap_or_default();
137
}
138
}
139
140
Logger {
141
debug,
142
trace,
143
output: output_type,
144
json: RefCell::new(JsonOutput {
145
logs: Vec::new(),
146
result: Result {
147
code: 0,
148
message: "".to_string(),
149
driver_path: "".to_string(),
150
browser_path: "".to_string(),
151
},
152
}),
153
minimal_json: RefCell::new(Default::default()),
154
}
155
}
156
157
pub fn error<T: Display>(&self, message: T) {
158
self.logger(message.to_string(), Level::Error);
159
}
160
161
pub fn warn<T: Display>(&self, message: T) {
162
self.logger(message.to_string(), Level::Warn);
163
}
164
165
pub fn info<T: Display>(&self, message: T) {
166
self.logger(message.to_string(), Level::Info);
167
}
168
169
pub fn debug<T: Display>(&self, message: T) {
170
self.logger(message.to_string(), Level::Debug);
171
}
172
173
pub fn debug_or_warn<T: Display>(&self, message: T, is_debug: bool) {
174
let level = if is_debug { Level::Debug } else { Level::Warn };
175
self.logger(message.to_string(), level);
176
}
177
178
pub fn trace<T: Display>(&self, message: T) {
179
self.logger(message.to_string(), Level::Trace);
180
}
181
182
fn logger(&self, message: String, level: Level) {
183
match self.output {
184
OutputType::Json => {
185
let trace = level <= Level::Trace && self.trace;
186
let debug = level <= Level::Debug && self.debug;
187
let other = level <= Level::Info;
188
if trace || debug || other {
189
self.json
190
.borrow_mut()
191
.logs
192
.push(self.create_json_log(message.to_string(), level));
193
}
194
if level == Level::Info || level <= Level::Error {
195
if message.starts_with(DRIVER_PATH) {
196
self.json.borrow_mut().result.driver_path =
197
self.clean_driver_path(&message);
198
} else if message.starts_with(BROWSER_PATH) {
199
self.json.borrow_mut().result.browser_path =
200
self.clean_browser_path(&message);
201
} else {
202
self.json.borrow_mut().result.message = message;
203
}
204
}
205
}
206
OutputType::Shell => {
207
if level == Level::Info {
208
println!("{}", message);
209
} else if level == Level::Error {
210
eprintln!("{}", message);
211
}
212
}
213
_ => {
214
if self.output == OutputType::Mixed && level == Level::Info || level <= Level::Error
215
{
216
if message.starts_with(DRIVER_PATH) {
217
self.minimal_json.borrow_mut().driver_path =
218
self.clean_driver_path(&message);
219
} else if message.starts_with(BROWSER_PATH) {
220
self.minimal_json.borrow_mut().browser_path =
221
self.clean_browser_path(&message);
222
} else {
223
self.minimal_json.borrow_mut().error = message.clone();
224
}
225
}
226
log::log!(level, "{}", message);
227
}
228
}
229
}
230
231
fn clean_driver_path(&self, message: &str) -> String {
232
message.replace(DRIVER_PATH, "")
233
}
234
235
fn clean_browser_path(&self, message: &str) -> String {
236
message.replace(BROWSER_PATH, "")
237
}
238
239
fn create_json_log(&self, message: String, level: Level) -> Logs {
240
Logs {
241
level: level.to_string().to_uppercase(),
242
timestamp: now_unix_timestamp(),
243
message,
244
}
245
}
246
247
fn get_json_blog<T>(&self, json_output: &T) -> String
248
where
249
T: Serialize,
250
{
251
serde_json::to_string_pretty(json_output).unwrap()
252
}
253
254
pub fn set_code(&self, code: i32) {
255
self.json.borrow_mut().result.code = code;
256
}
257
258
pub fn flush(&self) {
259
if self.output == OutputType::Json {
260
print!("{}", self.get_json_blog(&self.json));
261
} else if self.output == OutputType::Mixed {
262
print!("{}", self.get_json_blog(&self.minimal_json));
263
}
264
}
265
266
pub fn is_debug_enabled(&self) -> bool {
267
self.debug || self.trace
268
}
269
}
270
271