20 个版本
0.2.5 | 2021 年 4 月 29 日 |
---|---|
0.2.4 | 2020 年 7 月 7 日 |
0.2.3 | 2020 年 6 月 16 日 |
0.2.1 | 2020 年 1 月 29 日 |
0.1.5 | 2019 年 7 月 26 日 |
#282 in 调试
在 4 个代码包中使用(通过 realm)
60KB
1.5K SLoC
观察者
** Observer 是一个用于捕获 Rust 服务器可观察性的库
Observer 2.0 在行动
要使用 observer 2.0
- 在
Cargo.toml
中添加依赖项。
observer = "0.2.0"
observer_attribute = "0.1.6"
- 将这些依赖项导入
lib.rs
。
extern crate observer;
#[macro_use]
extern crate observer_attribute;
- 定义事件 JSON 文件并导出事件路径为 EVENTS_PATH。
export EVENTS_PATH="<Path of events.json file>"
event.json 文件
{
"foo__create_temp" : {
"critical" : true,
"result_type": "list",
"fields" : {
"id" : "string"
}
},
"update_temp" : {
"critical" : false,
"result_type": "i32",
"fields" : {
"id" : "string"
}
}
}
- 在项目中使用 observer
// Here namespace and with_result are optional parameter.
// If define namespace so in event file needs to define `foo__create_policy`
// If with_result defined so it log error also, if function returns an error.
use observer::prelude::*;
use observer::Result;
pub struct Temp;
#[observed(with_result)]
pub fn update_temp(id: &str) -> observer::Result<Temp> {
observe_field("id", id); // Need to tell type of id's value in event.json
observe_result(2314); // Need to tell type of result in event.json
observer::observe_span_log("Message from update temp");
Ok(Temp)
}
#[observed(namespace = "foo")]
pub fn create_temp(id: &str) -> observer::Result<Temp> {
observe_field("id", "4839");
observe_result(&vec![1,2,3,4]);
update_temp(id)
}
fn main(){
// define logger
let logger = observer::backends::logger::Logger::builder()
.with_path("/tmp/observer.log")
.with_stdout()
.build();
// Initialize observer with logger
observer::builder(Box::new(logger))
.create_context("main")
.init();
// Call your functions
let _result = create_temp("temp");
// End of the observer.
observer::end_context();
}
在 stdout
中应该是这样的
logger_initialized
context: main [0ms, 2020-01-29 11:10:54.728594 UTC]
foo__create_temp: 0ms
@id: "4839"
@@success: true
#result: [1,2,3,4]
update_temp: 0ms
@id: "temp"
@@success: true
#result: 2314
logs:
- 0ms: Message from update temp
在日志文件中应该看起来一样。
logger_initialized
context: main [0ms, 2020-01-29 11:10:54.728594 UTC]
foo__create_temp: 0ms
@id: "4839"
@@success: true
#result: [1,2,3,4]
update_temp: 0ms
@id: "temp"
@@success: true
#result: 2314
logs:
- 0ms: Message from update temp
Observer 0.1.*
在行动
要使用 Observer
- 必须定义事件文件(json 文件,强制)。
- 必须定义日志目录,否则它将默认为
/var/log/
。
首先,我们必须定义要观察的函数的事件。在这里,事件与函数名相同,在事件中,我们必须告诉哪些字段需要保存到面包屑中。关键意味着是否要保存此函数到本地或队列。如果是关键的,它将直接进入队列,否则 Observer 将将其保存到本地。
这里我们定义了两个事件 observer_me
和 observe_me_too
(与函数名相同)。
{
"observe_me" : {
"critical" : true,
"fields" : {
"foo" : "String",
"foo1" : "f32"
}
},
"observe_me_too" : {
"critical" : false,
"fields" : {
"foo1" : "i32"
}
}
}
// src/bin/main.rs
use observer::{
context::{observe_string, observe_i32, observe_f32},
observe::observe,
queue::Queue,
};
#[observed] // Need to define only this on top of fn which we want to observe
// Context reference is mandatory to pass in observer function.
// fn should be return Result type.
fn observe_me(ctx: &Context, other_params: i32)-> Result<String> {
// in "foo" can store only string value else it will give compile error
// It will this in breadcrumbs in Frame
observe_field("foo", "value".to_string());
// in "foo1" can store only f32 value else it will give compile error
// It will this in breadcrumbs in Frame
observe_field("foo1", 32.02);
some_other_fn_call();
// Observing this fn also and it will become a sub-frame of observe_me
observe_me_too(ctx);
Ok("observed")
}
fn some_other_fn_call() {}
#[observed]
fn observe_me_too(ctx: &Context) -> Result<i32> {
observe_field("foo1", 32);
Ok(12)
}
#[derive(Serialize, Debug, Deserialize)]
pub struct DemoQueue {
pub name: String,
}
#[typetag::serde(name = "Abc")]
impl Queue for DemoQueue {
// TODO: Will give complete definition of in next version surely
fn enqueue(&mut self, data: serde_json::Value) {
println!("Data: {}", data)
}
}
fn main() {
let ctx = Context::new(
"test_context".to_string(),
Box::new(DemoQueue{name: "Abrar".to_string()})
);
let _result = observe_me(&ctx, 12);
ctx.finalise();
}
我们首先调用 observer_me,然后在其中调用 observer_me_too。在上下文对象的情况下,Observer 将创建 observer_me 和 observer_me_too 的框架。因为 observer_me_too 是从 observer_me 内部调用的,所以它将成为 observer_me 的子框架。
它将根据事件的临界性创建日志目录,并将上下文保存到 log_dir_path/context,事件保存到 log_dir_path/observe_me 和 log_dir_path/observe_me_too。
上下文日志将看起来像这样
{
"frame": {
"breadcrumbs": {},
"key": "17eb437f-a5e2-4243-8dac-fa636429dcf9",
"result": null,
"sub_frames": [
{
"breadcrumbs": {
"foo": 32
},
"key": "59471fc8-3391-4619-b341-931658a2296e",
"result": 12,
"sub_frames": [
{
"breadcrumbs": {
"foo1": 32.02
},
"key": "399c8d43-16fb-4cd3-8273-b2666026f2f0",
"result": "observed",
"sub_frames": [],
"success": true,
"end_time": "2019-07-06T08:27:20.451786Z",
"id": "observe_me_too",
"start_time": "2019-07-06T08:27:20.451642Z"
}
],
"success": true,
"end_time": "2019-07-06T08:27:20.452680Z",
"id": "observe_me",
"start_time": "2019-07-06T08:27:20.451618Z"
}
],
"success": null,
"end_time": "2019-07-06T08:27:20.452683Z",
"id": "main",
"start_time": "2019-07-06T08:27:20.451590Z"
},
"key": "302a5760-107a-4826-8670-2efd57db27c2",
"queue": {
"type": "Abc",
"value": {
"name": "Abrar"
}
},
"id": "test_context"
}
框架/事件日志将看起来像这样
{
"key": "399c8d43-16fb-4cd3-8273-b2666026f2f0",
"id": "observe_me_too",
"breadcrumbs": {
"foo1": 32.02
},
"end_time": "2019-07-06T08:27:20.451786Z",
"result": "observed",
"start_time": "2019-07-06T08:27:20.451642Z",
"sub_frames": [],
"success": true
}
要运行它
它将取路径自 env、EVENTS_PATH(强制)和 LOG_DIR(如果不存在,则取 /var/log/)
EVENTS_PATH="" LOG_DIR="" cargo run --bin main
依赖项
~8–16MB
~221K SLoC