2022/01/15
[Rust]loggerを自作してpanic時のエラー検知を行う
概要
Rustでloggerを自作しました。
隙間時間を使ってコツコツ作りました。(思ったより時間がかかってしまいました。)
以下のような感じの機能を持たせています
- 複数の出力先を持たせる(2022/01/15では以下対応)
- 標準エラーに出力
- ファイルに出力
- TCP経由で出力(logstashなどを想定)
- HTTP(S)経由で出力(airbrake/errbitを想定)
- 拡張性
- このライブラリが提供するtraitを実装することで、ライブラリ利用先のプロジェクトで自前のloggerを拡張可能
- 非同期/同期出力
- httpやtcpでの出力機能があるため、ログ出力を非同期スレッドにて出力できるようにしています。(同じスレッドでの同期出力も可能)
- ログ出力時にbacktraceを出力可能
panic
時にbacktraceと共に、panic情報を出力(airbrake/errbitに通知)できるようにしました
使い方
Cargo.toml
[dependencies]
logger = { version = "0.1.0", git = "https://github.com/kumanote/logger-rs", branch = "main", features = ["airbrake"] }
use logger::default::DefaultLoggerBuilder;
use logger::prelude::*;
use logger::setup_panic_logger;
use logger::Level;
use actix_web::{web, App, HttpServer};
fn double_number(number_str: &str) -> i32 {
number_str
.parse::<i32>()
.map(|n| 2 * n)
.expect("number_str must be valid number string")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let mut builder = DefaultLoggerBuilder::new();
builder.is_async(true);
builder.level(Level::Debug);
builder.airbrake_host("https://api.airbrake.io".to_owned());
builder.airbrake_project_id("<YOUR PROJECT ID>".to_owned());
builder.airbrake_project_key("<YOUR API KEY>".to_owned());
builder.airbrake_environment("production".to_owned());
let _logger = builder.build();
setup_panic_logger();
HttpServer::new(move || App::new().configure(routes))
.bind("0.0.0.0:8000")?
.run()
.await
}
pub fn routes(app: &mut web::ServiceConfig) {
app.service(web::resource("/").route(web::get().to(index)));
}
pub async fn index(_req: web::HttpRequest) -> &'static str {
debug!("this is a simple debug log");
trace!("this is {}", "test");
let value1 = 5;
info!(key1 = value1);
let _number = double_number("NOT A NUMBER");
"OK"
}
DefaultLoggerBuilder
を使って、ロガーの設定を行います。- コンソール出力と(エラー時には)airbrake(errbit)に通知できるようにしています。
- 非同期でのログ出力を行うようにしています。
setup_panic_logger
でpanic時にクラッシュログをairbrake(errbit)に通知できるようにしました。
panic handler
panic時のログ出力のtips
setup_panic_logger
の中身です。
panic::set_hook
を使って、panic時にログ出力を行うように設定しています。
use crate::flush;
use crate::prelude::crash;
use std::panic::{self, PanicInfo};
pub fn setup_panic_logger() {
panic::set_hook(Box::new(move |pi: &PanicInfo<'_>| {
handle_panic(pi);
}));
}
fn handle_panic(panic_info: &PanicInfo<'_>) {
let details = format!("{}", panic_info);
crash!("{}", details);
flush();
}
今後は弊社の複数のrustプロジェクトで使っていこうと思います。
以上になります。
関連する記事
Concordiumノードをローカルで動かしてみた
Concordiumの調査のために、ローカルでソースコードをビルドしてノードを動かしてみました
[Rust]axumとdragonflyを使ったWebsocket Chatのサンプル実装
redis互換のdragonflyをPUBSUBとして利用して、Websocket Chatアプリのサンプル実装を行いました。
[Rust]TiDBを使ったサンプルアプリケーションの実装
RustからTiDBを使ったアプリケーションの実装を行いました。
[Rust]Google Cloud Storageを利用する
GCSやNFSのファイルを扱えるpackageをRustで実装しました。