Skip to content

Commit

Permalink
add app log
Browse files Browse the repository at this point in the history
  • Loading branch information
isaidsari committed Apr 14, 2024
1 parent 8d979fa commit eb8f037
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 15 deletions.
23 changes: 12 additions & 11 deletions proto/notification.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,9 @@ package remonproto;

service NotificationService {
rpc SendNotification(NotificationRequest) returns (NotificationResponse) {}
rpc Log(LogRequest) returns (LogResponse) {}
}

/*
enum Type {
NOTIFICATION = 0;
LOG = 1;
DEBUG = 2;
}
verbocity?
*/

message NotificationRequest {
string title = 1;
string body = 2;
Expand All @@ -27,3 +17,14 @@ message NotificationResponse {
bool success = 1;
optional string message = 2;
}

message LogRequest {
string level = 1;
string target = 2;
string message = 3;
}

message LogResponse {
bool success = 1;
optional string message = 2;
}
37 changes: 33 additions & 4 deletions src/grpc/grpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ use tonic::{transport::Server, Request, Response, Status};
use tonic_reflection::server as ReflectionServer;

use crate::{
monitor::persistence::fetch_monitor_configs, notification_service,
persistence::notification_logs::NotificationType,
monitor::persistence::fetch_monitor_configs,
notification_service,
persistence::{
app_logs::{insert_app_log, AppLog, LogLevel},
notification_logs::NotificationType,
},
};

use remonproto::{
notification_service_server::{
NotificationService as NotificationServiceImpl, NotificationServiceServer,
},
NotificationRequest, NotificationResponse,
LogRequest, LogResponse, NotificationRequest, NotificationResponse,
};

pub mod remonproto {
Expand Down Expand Up @@ -74,13 +78,38 @@ impl NotificationServiceImpl for NotificationService {
} else {
NotificationResponse {
success: false,
message: Some(format!("Failed to send notification: {}", res.err().unwrap())),
message: Some(format!(
"Failed to send notification: {}",
res.err().unwrap()
)),
}
};

// return the response
Ok(Response::new(response))
}

async fn log(&self, request: Request<LogRequest>) -> Result<Response<LogResponse>, Status> {
let log = request.into_inner();

info!("Received log message: {}", log.message);

let app_log = AppLog {
id: -1,
log_level: LogLevel::from_string(&log.level),
app_id: "source".to_string(), // TODO(isaidsari):
logged_at: chrono::Utc::now().timestamp(),
message: log.message,
target: log.target,
};

let res = insert_app_log(&app_log).await;

Ok(Response::new(LogResponse {
success: res.is_ok(),
message: Some("Log received".to_string()),
}))
}
}

pub async fn init() -> Result<(), Box<dyn std::error::Error>> {
Expand Down
2 changes: 2 additions & 0 deletions src/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use log::error;
use sqlx::sqlite::SqlitePoolOptions;
use sqlx::{Pool, Sqlite};

pub mod app_logs;
pub mod notification_logs;

const SQLITE_DBS_FOLDER_PATH: &str = "./db";
Expand Down Expand Up @@ -79,6 +80,7 @@ pub async fn init_db() -> Result<(), sqlx::Error> {
crate::monitor::persistence::init_db(&conn).await?;

notification_logs::create_notification_logs_table(&conn).await?;
app_logs::create_app_logs_table(&conn).await?;

Ok(())
}
89 changes: 89 additions & 0 deletions src/persistence/app_logs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use super::{get_default_sql_connection, SQLConnection};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, sqlx::Type, Clone, PartialEq, PartialOrd)]
#[serde(rename_all = "lowercase")]
pub enum LogLevel {
Trace,
Debug,
Info,
Warning,
Error,
}

impl LogLevel {
pub fn from_log_crate_level(s: &log::Level) -> LogLevel {
match s {
log::Level::Trace => LogLevel::Trace,
log::Level::Debug => LogLevel::Debug,
log::Level::Info => LogLevel::Info,
log::Level::Warn => LogLevel::Warning,
log::Level::Error => LogLevel::Error,
}
}
pub fn from_string(level: &str) -> LogLevel {
match level.to_lowercase().as_str() {
"error" => LogLevel::Error,
"warn" => LogLevel::Warning,
"warning" => LogLevel::Warning,
"info" => LogLevel::Info,
"debug" => LogLevel::Debug,
"trace" => LogLevel::Trace,
_ => LogLevel::Info,
}
}
}

#[derive(Debug, Serialize, Deserialize, sqlx::FromRow, Clone)]
pub struct AppLog {
pub id: i64,
pub log_level: LogLevel,
pub app_id: String,
pub logged_at: i64,
pub message: String,
// like function name or crate name
// e.g. remon_server::monitor::config_exceeds, sqlx::query
pub target: String,
}

const APP_LOGS_TABLE_NAME: &str = "app_logs";

pub async fn insert_app_log(log: &AppLog) -> Result<(), sqlx::Error> {
let conn = get_default_sql_connection().await?;

let statement = format!(
"INSERT INTO {}
(log_level, app_id, logged_at, message, target)
VALUES (?, ?, ?, ?, ?)",
APP_LOGS_TABLE_NAME
);

sqlx::query(&statement)
.bind(&log.log_level)
.bind(&log.app_id)
.bind(&log.logged_at)
.bind(&log.message)
.bind(&log.target)
.execute(&conn)
.await?;

Ok(())
}

pub(super) async fn create_app_logs_table(conn: &SQLConnection) -> Result<(), sqlx::Error> {
let statement = format!(
"CREATE TABLE IF NOT EXISTS {} (
id INTEGER PRIMARY KEY AUTOINCREMENT,
log_level INTEGER NOT NULL,
app_id TEXT NOT NULL,
logged_at INTEGER NOT NULL,
message TEXT NOT NULL,
target TEXT NOT NULL
)",
APP_LOGS_TABLE_NAME
);

sqlx::query(&statement).execute(conn).await?;

Ok(())
}

0 comments on commit eb8f037

Please sign in to comment.