malwaredb 0.3.2

Service for storing malicious, benign, or unknown files and related metadata and relationships.
// SPDX-License-Identifier: Apache-2.0

#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
#![deny(clippy::all)]
#![deny(clippy::cargo)]
#![deny(clippy::pedantic)]

pub(crate) mod cli;
#[cfg(feature = "admin-gui")]
pub(crate) mod gui;

use crate::cli::LogOptions;

use std::process::ExitCode;

use clap::Parser;
use tracing_subscriber::filter::{filter_fn, FilterExt};
use tracing_subscriber::fmt::format::FmtSpan;
use tracing_subscriber::{prelude::*, EnvFilter};

/// MDB version
pub const MDB_VERSION: &str = env!("CARGO_PKG_VERSION");

pub(crate) fn init_logger(logger: Option<LogOptions>) {
    let env_filter = if let Some(logger) = &logger {
        EnvFilter::builder().parse_lossy(logger.log_filter.as_ref().unwrap_or(&String::new()))
    } else {
        EnvFilter::from_default_env()
    };

    let target_filter = filter_fn(|meta| {
        let target = meta.target();
        [
            "malwaredb",
            "malwaredb_server",
            "malwaredb_types",
            #[cfg(debug_assertions)]
            "deadpool_postgres",
            #[cfg(debug_assertions)]
            "postgres",
            #[cfg(all(feature = "sqlite", debug_assertions))]
            "rusqlite",
            #[cfg(feature = "vt")]
            "malwaredb_virustotal",
        ]
        .into_iter()
        .any(|name| target.eq(name) || target.starts_with(&format!("{name}::")))
    });
    let log_filter = env_filter.and(target_filter);

    if let Some(logger) = logger {
        let fmt_layer = tracing_subscriber::fmt::layer()
            .pretty()
            .with_writer(move || -> Box<dyn std::io::Write> {
                match logger.log_target {
                    cli::LogTarget::Stdout => Box::new(std::io::stdout()),
                    cli::LogTarget::Stderr => Box::new(std::io::stderr()),
                }
            })
            .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
            .with_filter(log_filter);

        #[cfg(target_os = "linux")]
        if let Ok(layer) = tracing_journald::layer() {
            tracing_subscriber::registry()
                .with(fmt_layer)
                .with(layer)
                .init();
        } else {
            tracing_subscriber::registry().with(fmt_layer).init();
        }

        #[cfg(target_os = "windows")]
        if let Ok(eventlog) = tracing_layer_win_eventlog::EventLogLayer::new("MalwareDB Service") {
            tracing_subscriber::registry()
                .with(fmt_layer)
                .with(eventlog)
                .init();
        } else {
            tracing_subscriber::registry().with(fmt_layer).init();
        }

        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
        tracing_subscriber::registry().with(fmt_layer).init();
    } else {
        let fmt_layer = tracing_subscriber::fmt::layer()
            .pretty()
            .with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
            .with_filter(log_filter);
        #[cfg(target_os = "linux")]
        if let Ok(layer) = tracing_journald::layer() {
            tracing_subscriber::registry()
                .with(fmt_layer)
                .with(layer)
                .init();
        } else {
            tracing_subscriber::registry().with(fmt_layer).init();
        }

        #[cfg(target_os = "windows")]
        if let Ok(eventlog) = tracing_layer_win_eventlog::EventLogLayer::new("MalwareDB Service") {
            tracing_subscriber::registry()
                .with(fmt_layer)
                .with(eventlog)
                .init();
        } else {
            tracing_subscriber::registry().with(fmt_layer).init();
        }

        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
        tracing_subscriber::registry().with(fmt_layer).init();
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<ExitCode> {
    let app = cli::Options::parse();
    init_logger(Some(app.logger.clone()));

    app.execute().await
}