Added logging to bot

+ Cleaned up error handling to make it easier to handle multiple error levels
main
Joey Hines 2021-12-12 11:55:09 -07:00
parent 199516f3cc
commit c45bb592db
No known key found for this signature in database
GPG Key ID: 80F567B5C968F91B
10 changed files with 124 additions and 80 deletions

3
Cargo.lock generated
View File

@ -442,11 +442,13 @@ dependencies = [
"async-trait",
"config",
"geoffrey_models",
"log",
"reqwest",
"serde 1.0.130",
"serde_json",
"serde_plain",
"serenity",
"simple_logger",
"structopt",
"tokio",
]
@ -471,6 +473,7 @@ name = "geoffrey_models"
version = "0.1.0"
dependencies = [
"chrono",
"log",
"serde 1.0.130",
"serde_json",
]

View File

@ -2,37 +2,7 @@ use log::{LevelFilter, SetLoggerError};
use serde::{Deserialize, Serialize};
use simple_logger::SimpleLogger;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum LogLevel {
None,
Warn,
Info,
Debug,
}
impl From<&str> for LogLevel {
#[allow(clippy::wildcard_in_or_patterns)]
fn from(s: &str) -> Self {
let s = s.to_lowercase();
match s.as_str() {
"warn" | "w" => LogLevel::Warn,
"info" | "i" => LogLevel::Info,
"debug" | "d" => LogLevel::Debug,
"none" | _ => LogLevel::None,
}
}
}
impl From<LogLevel> for LevelFilter {
fn from(l: LogLevel) -> Self {
match l {
LogLevel::None => LevelFilter::Off,
LogLevel::Warn => LevelFilter::Warn,
LogLevel::Info => LevelFilter::Info,
LogLevel::Debug => LevelFilter::Debug,
}
}
}
use geoffrey_models::logging::LogLevel;
pub fn init_logging(log_level: LogLevel) -> Result<(), SetLoggerError> {
SimpleLogger::new()

View File

@ -1,24 +1,28 @@
mod commands;
mod config;
mod context;
mod helper;
mod logging;
use crate::commands::add_token::AddToken;
use crate::commands::{command_filter, Command};
use crate::config::GeoffreyAPIConfig;
use crate::context::Context;
use crate::logging::{init_logging, LogLevel};
use geoffrey_models::models::parameters::add_token_params::AddTokenParams;
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
use geoffrey_models::models::token::Permissions;
use std::convert::TryFrom;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use structopt::StructOpt;
use geoffrey_models::logging::LogLevel;
use geoffrey_models::models::parameters::add_token_params::AddTokenParams;
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
use geoffrey_models::models::token::Permissions;
use crate::commands::{Command, command_filter};
use crate::commands::add_token::AddToken;
use crate::config::GeoffreyAPIConfig;
use crate::context::Context;
use crate::logging::init_logging;
mod commands;
mod config;
mod context;
mod helper;
mod logging;
pub type Result<T> = std::result::Result<T, GeoffreyAPIError>;
#[derive(Debug, StructOpt, Clone)]

View File

@ -16,3 +16,5 @@ serde_plain = "1.0.0"
async-trait = "0.1.51"
config = "0.11.0"
structopt = "0.3.21"
log = "0.4.14"
simple_logger = "1.13.0"

View File

@ -98,33 +98,29 @@ pub trait BotCommand {
resp
} else {
match err {
CommandError::GeoffreyApi(err) => match err {
GeoffreyAPIError::PlayerNotRegistered => {
CommandError::GeoffreyApi(GeoffreyAPIError::PlayerNotRegistered) => {
"You need to register before using this command!".to_string()
}
GeoffreyAPIError::EntryNotFound => {
CommandError::GeoffreyApi(GeoffreyAPIError::EntryNotFound) => {
"Couldn't find that, maybe look for something that exists?".to_string()
}
GeoffreyAPIError::PermissionInsufficient => {
CommandError::GeoffreyApi(GeoffreyAPIError::PermissionInsufficient) => {
"Looks like you don't have permission for that.".to_string()
}
GeoffreyAPIError::EntryNotUnique => {
CommandError::GeoffreyApi(GeoffreyAPIError::EntryNotUnique) => {
"Slow down, I already know that thing. Try a new name.".to_string()
}
GeoffreyAPIError::DatabaseError(_) => "How the heck u mess that up".to_string(),
GeoffreyAPIError::TokenNotAuthorized => "WHO ARE YOU????".to_string(),
GeoffreyAPIError::MultipleLocationsMatch => {
CommandError::GeoffreyApi(GeoffreyAPIError::MultipleLocationsMatch) => {
"I couldn't match a single location, narrow down your search".to_string()
}
GeoffreyAPIError::ParameterInvalid(err) => {
CommandError::GeoffreyApi(GeoffreyAPIError::ParameterInvalid(err)) => {
format!(
"Welp, you some how messed up the {} parameter, great job",
err
)
}
},
_ => {
println!("GeoffreyBot got an unhandled error: {}", err);
log::warn!("GeoffreyBot got an unhandled error: {}", err);
format!("OOPSIE WOOPSIE!! Uwu We made a fucky wucky!! A wittle fucko boingo! The admins at our \
headquarters are working VEWY HAWD to fix this! (Error in command {})", Self::command_name())
}
@ -149,6 +145,8 @@ pub trait BotCommand {
) -> Result<String, CommandError> {
let mut args = Self::process_arguments(command_interact).await?;
log::info!("Running command {}, with args {:?}", Self::command_name(), args);
args.set_token(ctx.cfg.api.token.clone());
args.set_user_id(user_id);

View File

@ -0,0 +1,11 @@
use log::{LevelFilter, SetLoggerError};
use simple_logger::SimpleLogger;
use geoffrey_models::logging::LogLevel;
pub fn init_logging(log_level: LogLevel) -> Result<(), SetLoggerError> {
SimpleLogger::new()
.with_level(LevelFilter::Warn)
.with_module_level("geoffrey_bot", log_level.into())
.init()
}

View File

@ -1,6 +1,7 @@
mod bot;
mod configs;
mod context;
mod logging;
use crate::bot::create_commands;
use crate::configs::GeoffreyBotConfig;
@ -22,12 +23,22 @@ use serenity::{
};
use std::path::PathBuf;
use structopt::StructOpt;
use geoffrey_models::logging::LogLevel;
use crate::logging::init_logging;
#[derive(Debug, StructOpt, Clone)]
#[structopt(name = "GeoffreyBot", about = "Geoffrey Discord Bot")]
struct Args {
#[structopt(env = "GEOFFREY_BOT_CONFIG", parse(from_os_str))]
config: PathBuf,
#[structopt(
short,
long,
env = "GEOFFREY_LOG_LEVEL",
parse(from_str),
default_value = "Info"
)]
log_level: LogLevel,
}
struct HttpClient;
@ -41,13 +52,13 @@ struct Handler;
#[async_trait]
impl EventHandler for Handler {
async fn ready(&self, ctx: Context, ready: Ready) {
println!("{} is connected!", ready.user.name);
log::info!("{} is connected!", ready.user.name);
let commands = create_commands(&ctx).await.unwrap();
println!("The following bot have been registered:");
log::debug!("The following bot have been registered:");
for command in commands {
println!(
log::debug!(
"{}: {} - {:?}",
command.name, command.description, command.options
);
@ -92,7 +103,7 @@ impl EventHandler for Handler {
.await
.unwrap()
} else if let Interaction::Ping(_) = interaction {
println!("Ping recv'ed");
// do nothing
}
}
}
@ -100,21 +111,30 @@ impl EventHandler for Handler {
#[tokio::main]
async fn main() {
let args: Args = Args::from_args();
init_logging(args.log_level).expect("Unable to init logging");
let cfg = match GeoffreyBotConfig::new(args.config.as_path()) {
Ok(cfg) => cfg,
Err(e) => {
println!("Error opening config: {}", e);
log::warn!("Error opening config: {}", e);
return;
}
};
let mut client = Client::builder(cfg.discord.token.clone())
let client = Client::builder(cfg.discord.token.clone())
.event_handler(Handler)
.application_id(cfg.discord.app_id)
.await
.expect("Error creating Geoffrey client");
.await;
let mut client = match client {
Ok(client) => client,
Err(e) => {
log::warn!("Unable to init serenity client: {}", e);
return;
}
};
// Block for initializing global data
{
let mut data = client.data.write().await;
@ -124,7 +144,7 @@ async fn main() {
})
}
if let Err(why) = client.start().await {
println!("Client error: {:?}", why);
if let Err(e) = client.start().await {
log::warn!("Client error: {:?}", e);
}
}

View File

@ -10,3 +10,4 @@ edition = "2018"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4.19", features = ["serde"] }
log = "0.4.14"

View File

@ -4,6 +4,7 @@ use serde::Serialize;
use std::fmt::Debug;
pub mod models;
pub mod logging;
pub trait GeoffreyDatabaseModel: Serialize + DeserializeOwned + Debug {
fn id(&self) -> Option<u64>;

View File

@ -0,0 +1,34 @@
use log::LevelFilter;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum LogLevel {
None,
Warn,
Info,
Debug,
}
impl From<&str> for LogLevel {
#[allow(clippy::wildcard_in_or_patterns)]
fn from(s: &str) -> Self {
let s = s.to_lowercase();
match s.as_str() {
"warn" | "w" => LogLevel::Warn,
"info" | "i" => LogLevel::Info,
"debug" | "d" => LogLevel::Debug,
"none" | _ => LogLevel::None,
}
}
}
impl From<LogLevel> for LevelFilter {
fn from(l: LogLevel) -> Self {
match l {
LogLevel::None => LevelFilter::Off,
LogLevel::Warn => LevelFilter::Warn,
LogLevel::Info => LevelFilter::Info,
LogLevel::Debug => LevelFilter::Debug,
}
}
}