Crates.io | observer |
lib.rs | observer |
version | 0.2.5 |
source | src |
created_at | 2019-07-04 11:26:53.085473 |
updated_at | 2021-04-29 08:28:16.40064 |
description | Observer |
homepage | |
repository | https://github.com/ackotech/observer |
max_upload_size | |
id | 145845 |
size | 60,821 |
** Observer is a library to capture observability of rust servers
To use 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;
export EVENTS_PATH="<Path of events.json file>"
event.json file
{
"foo__create_temp" : {
"critical" : true,
"result_type": "list",
"fields" : {
"id" : "string"
}
},
"update_temp" : {
"critical" : false,
"result_type": "i32",
"fields" : {
"id" : "string"
}
}
}
// 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();
}
In stdout
it should look like
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
In log file it should look the same.
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
0.1.*
in actionTo use Observer
/var/log/
.Firstly We have to define an events to observe functions. Here Events are nothing but same as function name and in events we have tell which fields has be save in breadcrumbs. And critical means whether to save this function locally or queue. If critical It will go directly to queue else Observer will save it local.
Here we have defined to events observer_me
and observe_me_too
(same as function name).
{
"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();
}
We are calling observer_me as first function and observer_me_too inside it. In case of Context Object Observer will create frame observer_me and observer_me_too. Because observer_me_too is calling calling inside from observer_me so it will become sub-frame of observer_me.
It will create log dir by given path or default(/var/log/) and save context into log_dir_path/context and events in log_dir_path/observe_me and log_dir_path/observe_me_too based of criticality of of an event.
{
"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
}
It will take to path from env, EVENTS_PATH(Mandatory) and LOG_DIR (If not exists so it will take /var/log/)
EVENTS_PATH="" LOG_DIR="" cargo run --bin main