Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example and CustomLogger #1

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
Language: Cpp
BasedOnStyle: Google
...
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@
# Executables
*.exe
*.out
*.app
*.app

# Logs
logs/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "external/spdlog"]
path = external/spdlog
url = https://github.com/gabime/spdlog.git
51 changes: 51 additions & 0 deletions example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "logfmt.h"

#define toFile false

// Compile with "g++ example.cpp logfmt.cpp -o example -Wall -Wextra -pedantic
// -std=c++17 -pthread -Iexternal/spdlog/include -fmax-errors=1 -O3
// -march=native" dont forget to create logs folder if logging to file

int main() {
std::string a = "testing";
float float_test = 2.8;
long long_test = 100;
logfmt log("test", toFile);

spdlog::set_level(spdlog::level::trace);
log.with_field(log.custom_field = {{"animal", "walrus"}, {"total", 100}})
.info("INFO of WALRUS and its total");
log.info("No Walrus");
log.with_field(log.custom_field = {{"animal", "dog"}, {"total", float_test}})
.warn("WARN of DOG and its total");
log.warn("No Dog");

log.JSON_output(); // output in JSON format
log.with_field(log.custom_field = {{"animal", "cat"}, {"total", long_test}})
.critical("CRITICAL of CAT and its total");
log.critical("No Cat");
log.with_field(log.custom_field = {{"animal", "falcon"}, {"total", 10}})
.error("ERROR of FALCON and its total");
log.error("No Falcon");

auto staticformat = log.with_field(log.custom_field = {{"float", float_test},
{"long", long_test},
{"string", a}});
staticformat.info("This is INFO with custom key");
staticformat.debug("This is DEBUG with custom key");
staticformat.trace("This is TRACE with custom key");
staticformat.warn("This is WARN with custom key");
staticformat.critical("This is CRITICAL with custom key");
staticformat.error("This is ERROR with custom key");

log.default_output();
auto staticformat2 = log.with_field(log.custom_field = {{"animal", "griffin"},
{"rider", "azure"},
{"weapon", "spear"}});
staticformat2.info("This is INFO with custom key");
staticformat2.debug("This is DEBUG with custom key");
staticformat2.trace("This is TRACE with custom key");
staticformat2.warn("This is WARN with custom key");
staticformat2.critical("This is CRITICAL with custom key");
staticformat2.error("This is ERROR with custom key");
}
1 change: 1 addition & 0 deletions external/spdlog
Submodule spdlog added at 8179b2
195 changes: 195 additions & 0 deletions logfmt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#include "logfmt.h"

////////////////////////////////////////////////////////////////////////////////////////////////////////

// class Entry

// private
std::string logfmt::Entry::add_quotation(std::string msg) {
return "\"" + msg + "\"";
}

void logfmt::Entry::process_key(std::string& msg) {
std::string pattern = " ";

for (auto& [key, val] : entry_field) {
pattern = pattern + cast_key(key, val);
}

if (JSON) {
msg = add_quotation(msg);
}

msg = msg + pattern;
}

std::string logfmt::Entry::cast_key(std::string key, std::any val) {
std::string custom_string;

if (JSON) {
custom_string = ", " + add_quotation(key) + " : ";
} else {
custom_string = custom_string + key + " = ";
}
if (val.type() == typeid(char)) {
custom_string = custom_string + "\"";
custom_string += (std::any_cast<char>(val));
custom_string = custom_string + "\" ";
} else if (val.type() == typeid(const char*)) {
std::string temp(std::any_cast<const char*>(val));
custom_string = custom_string + add_quotation(temp) + " ";
} else if (val.type() == typeid(int)) {
custom_string =
custom_string + std::to_string(std::any_cast<int>(val)) + " ";
} else if (val.type() == typeid(float)) {
custom_string =
custom_string + std::to_string(std::any_cast<float>(val)) + " ";
} else if (val.type() == typeid(double)) {
custom_string =
custom_string + std::to_string(std::any_cast<double>(val)) + " ";
} else if (val.type() == typeid(bool)) {
if (std::any_cast<bool>(val) == 1) {
custom_string = custom_string + "true ";
} else if (std::any_cast<bool>(val) == 0) {
custom_string = custom_string + "false ";
}
} else if (val.type() == typeid(std::string)) {
custom_string =
custom_string + add_quotation(std::any_cast<std::string>(val)) + " ";
} else if (val.type() == typeid(long)) {
custom_string =
custom_string + std::to_string(std::any_cast<long>(val)) + " ";
}

return custom_string;
}

// public
logfmt::Entry::Entry() {
// default ctor (not used)
}

logfmt::Entry::Entry(std::shared_ptr<spdlog::logger>& log, bool JSON) {
entry_log = log;
this->JSON = JSON;
}

logfmt::Entry& logfmt::Entry::with_field(
std::map<std::string, std::any>& key_map) {
entry_field = key_map;
return *this;
}
void logfmt::Entry::info(std::string msg) {
process_key(msg);
entry_log->info(msg);
}

void logfmt::Entry::trace(std::string msg) {
process_key(msg);
entry_log->trace(msg);
}

void logfmt::Entry::debug(std::string msg) {
process_key(msg);
entry_log->debug(msg);
}

void logfmt::Entry::warn(std::string msg) {
process_key(msg);
entry_log->warn(msg);
}

void logfmt::Entry::error(std::string msg) {
process_key(msg);
entry_log->error(msg);
}

void logfmt::Entry::critical(std::string msg) {
process_key(msg);
entry_log->critical(msg);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////
// logfmt implementation

// ctor
logfmt::logfmt(std::string name, bool to_file) {
if (to_file) {
logger = spdlog::basic_logger_mt(name, "logs/basic-log.txt");
} else {
logger = spdlog::stdout_color_mt(name);
}
write_file = to_file;
JSON_status = false;
}

// function
void logfmt::JSON_output() {
JSON_status = true;
logger->set_pattern(JSON_formatter());
}

void logfmt::default_output() {
JSON_status = false;
logger->set_pattern("%+");
}

logfmt::Entry& logfmt::with_field(std::map<std::string, std::any>& key_map) {
logger_entry = Entry(logger, JSON_status);
return logger_entry.with_field(key_map);
}

std::string logfmt::add_quotation(std::string msg) {
return "\"" + msg + "\" ";
}

std::string logfmt::JSON_formatter() {
return "{ \"date\" : \"%d-%m-%Y\" , \"time\" : \"%H:%M:%S\" , \"name\" : "
"\"%n\" , \"level\" : \"%^%l%$\" , \"message\" : %v}";
}

// basic logging
void logfmt::info(std::string msg) {
if (JSON_status) {
msg = add_quotation(msg);
}

logger->info(msg);
}

void logfmt::trace(std::string msg) {
if (JSON_status) {
msg = add_quotation(msg);
}

logger->trace(msg);
}
void logfmt::debug(std::string msg) {
if (JSON_status) {
msg = add_quotation(msg);
}

logger->debug(msg);
}
void logfmt::warn(std::string msg) {
if (JSON_status) {
msg = add_quotation(msg);
}

logger->warn(msg);
}
void logfmt::error(std::string msg) {
if (JSON_status) {
msg = add_quotation(msg);
}

logger->error(msg);
}
void logfmt::critical(std::string msg) {
if (JSON_status) {
msg = add_quotation(msg);
}

logger->critical(msg);
}
65 changes: 65 additions & 0 deletions logfmt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once

#include <any>
#include <iostream>
#include <map>
#include <typeinfo>
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"

class logfmt {
private:
// member of logfmt
class Entry {
// member of Entry
private:
std::map<std::string, std::any> entry_field;
std::shared_ptr<spdlog::logger> entry_log;
bool JSON;
// function
std::string add_quotation(std::string msg); // add quotation into message
void process_key(std::string& msg); // process the custom key
std::string cast_key(std::string key,
std::any val); // cast any type to its original type
public:
// default ctor
Entry();
// ctor with parameter
Entry(std::shared_ptr<spdlog::logger>& log, bool JSON);
// function
Entry& with_field(std::map<std::string, std::any>& key_map);
void info(std::string msg);
void trace(std::string msg);
void debug(std::string msg);
void warn(std::string msg);
void error(std::string msg);
void critical(std::string msg);
};
Entry logger_entry;
std::shared_ptr<spdlog::logger> logger;
bool JSON_status;
bool write_file; // make this true to write log into file

// private function
std::string JSON_formatter(); // make the log in JSON format
std::string add_quotation(std::string msg);

public:
// member
std::map<std::string, std::any> custom_field;
// ctor
logfmt(std::string name, bool to_file);
// function
void JSON_output(); // make output into JSON format
void default_output(); // make output into default format
logfmt::Entry& with_field(std::map<std::string, std::any>& key_map);

// basic logging
void info(std::string msg);
void trace(std::string msg);
void debug(std::string msg);
void warn(std::string msg);
void error(std::string msg);
void critical(std::string msg);
};