/* Zadanie dodatkowe na przedmiot ZPR
 * Autor: Damian Baraniak
 * Data: 1.06.2024
 *
 * Przykład wykorzystania biblioteki boost::log
 * Biblioteka umożliwa rozbudowane sposoby na rejestrowanie zdarzeń, monitorowanie oraz debugowanie aplikacji.
 *
 * Do zbudowania programu na systemie Linux potrzebne są zainstalowane biblioteki Boost.
 * Program można skompilować komendą:
 * g++ -std=c++11 -DBOOST_LOG_DYN_LINK -o boost-bench-mt main.cpp -lpthread -lboost_log -lboost_log_setup -lboost_system -lboost_thread
 *
 * Źródła:
 * - Tutorial biblioteki: https://www.boost.org/doc/libs/1_85_0/libs/log/doc/html/log/tutorial.html
 * - Dokumentacja: https://www.boost.org/doc/libs/1_85_0/libs/log/doc/html/log/reference.html
 */

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/attributes.hpp>

namespace logging = boost::log;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace attrs = boost::log::attributes;
namespace keywords = boost::log::keywords;

void simple_logging(){
    /* Najprostszym sposobem dodana funckji logowania do aplikacji jest wykorzystanie makr przygotowanych przez twórców.
       Każda wiadomość ma określony poziom krytyczności, można wykorzystać skalę z biblioteki:
        enum severity_level
        {   trace,
            debug,
            info,
            warning,
            error,
            fatal};
        albo stworzyć własną.
     */

    // Wyświetlane informacje można ograniczyć, ustawiając poziom krytyczności.
    // Tak ustawiony filtr, nie przepuści wiadomości o niższym poziomie niż warning.
    logging::core::get()->set_filter
            (
                    logging::trivial::severity >= logging::trivial::warning
            );
    BOOST_LOG_TRIVIAL(trace) << "Trace level message";
    BOOST_LOG_TRIVIAL(debug) << "Debug level message";
    BOOST_LOG_TRIVIAL(info) << "Info level message";
    BOOST_LOG_TRIVIAL(warning) << "Warning level message";
    BOOST_LOG_TRIVIAL(error) << "Error level message";
    BOOST_LOG_TRIVIAL(fatal) << "Fatalerror message";

    // Cofnięcie globalnego filtra
    logging::core::get()->reset_filter();
}

// Można utworzyć własne poziomy krytyczności
enum severity_level
{
    normal,
    warning,
    error,
    fatal
};


typedef logging::sources::severity_logger<severity_level> logger_t;


void sinks_and_loggers(){
    /*
     * Bezwarunkowe wyświetlanie komunikatów do konsoli, nie sprawdza się w większych aplikacjach, dlatego można konfigurować
     * własne studnie logowania. Biblioteka dostarcza domyślną studnie, którą wykorzystano w simple_logging, ale od momentu
     * ustawienia nowych nie będzie ona już dostępna. Może istnieć kilka równoległych studnii, każda na swój sposób obsłuży
     * dostarczoną wiadomość.
     * Dla każdej studnii można ustawić filtrowanie wiadomości, format komunikatów
     */


    logging::add_common_attributes();
// Stworzenie pliku z logami, zapewniającym własne formatowanie. Można też zautoamtyzować tworzenie plików np. kiedy przekroczy
// objętość, albo o odpowiedniej godzinie.

        auto file_sink = logging::add_file_log(
            keywords::file_name = "all_log_%N.log",
            keywords::format = "[ALL LOG] [%LineID%]: %Message%",
            keywords::auto_flush = true
    );


// Istnieje również studnia pozwalajaca wyświetlać wiadoomści w kosoli, dodano własne formatowania
// oraz filtrowanie wiadomości
    auto console_sink = logging::add_console_log(
                std::cout,
                keywords::format = "[LOG] [%TimeStamp%]: %Message%"
                                                 );
    console_sink->set_filter(
            expr::attr<severity_level>("Severity") >= warning

    );

/*
 * Biblioteka boost log dostarcza obiekty loggera, do których przekazywane są generowane komunikaty. Występują one w wersjach jedno i wielowątkowych
 */
    logger_t logger;
//Przykładowe stworzenie rekordu w logerze
    logging::record rec = logger.open_record();
    if (rec)
    {
        logging::record_ostream strm(rec);
        strm << "Creating a record and using simple logger";
        strm.flush();
        logger.push_record(boost::move(rec));
    }
// Zamiast pisać wszystko można wykorzstywać przygotowane przez twórców makra. Można również tworzyć swoje własne makra, co zalecają twórcy.
    BOOST_LOG_SEV(logger, normal) << "This is simple_logging normal message";
    BOOST_LOG_SEV(logger, warning) << "This is simple_logging warning message";
    BOOST_LOG_SEV(logger, fatal) << "This is an error message";
}


int main(){

    simple_logging();

    sinks_and_loggers();

    return 0;

}