mirror of
https://github.com/KjellKod/g3log.git
synced 2024-12-12 10:23:50 +01:00
parent
0e3fef50bb
commit
fec09b2bba
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@ -47,7 +47,7 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@ -58,7 +58,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@ -72,4 +72,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
|
|
||||||
***PULL REQUEST DESCRIPTION***
|
# PULL REQUEST DESCRIPTION
|
||||||
|
|
||||||
`ADD CONTENT HERE TO DESCRIBE THE PURPOSE OF THE PULL REQUEST`
|
`ADD CONTENT HERE TO DESCRIBE THE PURPOSE OF THE PULL REQUEST`
|
||||||
|
|
||||||
**Testing Advice**
|
# Testing
|
||||||
|
|
||||||
|
- [] This new/modified code was covered by unit tests.
|
||||||
|
|
||||||
|
- [] (insight) Was all tests written using TDD (Test Driven Development) style?
|
||||||
|
|
||||||
|
- [] The CI (Windows, Linux, OSX) are working without issues.
|
||||||
|
|
||||||
|
- [] Was new functionality documented?
|
||||||
|
|
||||||
|
- [] The testing steps 1 - 2 below were followed
|
||||||
|
|
||||||
_step 1_
|
_step 1_
|
||||||
|
|
||||||
@ -17,14 +27,4 @@ _step 2: use one of these alternatives to run tests:_
|
|||||||
|
|
||||||
- Cross-Platform: `ctest`
|
- Cross-Platform: `ctest`
|
||||||
- or `ctest -V` for verbose output
|
- or `ctest -V` for verbose output
|
||||||
- Linux: `make test`
|
- Linux: `make test`
|
||||||
|
|
||||||
|
|
||||||
***CHECKLIST TO COMPLETE***
|
|
||||||
- [ ] **TDD**: New/modified code must be backed down with unit test - preferably _Test Driven Development_ style development)
|
|
||||||
- [ ] **Documentation**: All new/modified functionality should be backed up with API documentation (API.markdown or README.markdown)
|
|
||||||
|
|
||||||
|
|
||||||
**Cross-Platform Testing**
|
|
||||||
- [ ] CI GitActions: (Linux, OSX) + AppVeyor-CI (Windows)\
|
|
||||||
- [ ] Local/VM testing, at least one of the following: Windows, Linux, OSX
|
|
428
docs/g3log.md
428
docs/g3log.md
@ -1,214 +1,214 @@
|
|||||||
# How to use G3log
|
# How to use g3log
|
||||||
G3log is an asynchronous logger with dynamic sinks
|
G3log is an asynchronous logger with dynamic sinks
|
||||||
|
|
||||||
|
|
||||||
## Example USAGE
|
## Example USAGE
|
||||||
#### Optional to use either streaming or printf-like syntax
|
#### Optional to use either streaming or printf-like syntax
|
||||||
```
|
```
|
||||||
LOG(INFO) << "streaming API is as easy as ABC or " << 123;
|
LOG(INFO) << "streaming API is as easy as ABC or " << 123;
|
||||||
|
|
||||||
LOGF(WARNING, "Printf-style syntax is also %s", "available");
|
LOGF(WARNING, "Printf-style syntax is also %s", "available");
|
||||||
```
|
```
|
||||||
|
|
||||||
## <a name="what-g3log-is">What G3Log is</a>
|
## <a name="what-g3log-is">What g3Log is</a>
|
||||||
|
|
||||||
* ***G3log*** is the acting name for the third version of g2log and it stands for **g3log with dynamic sinks**
|
* ***G3log*** is the acting name for the third version of g2log and it stands for **g3log with dynamic sinks**
|
||||||
* G3log is an asynchronous, "crash-safe" logger. You can read more about it here [[g2log version]](
|
* G3log is an asynchronous, "crash-safe" logger. You can read more about it here [[g2log version]](
|
||||||
http://www.codeproject.com/Articles/288827/g2log-An-efficient-asynchronous-logger-using-Cplus)
|
http://www.codeproject.com/Articles/288827/g2log-An-efficient-asynchronous-logger-using-Cplus)
|
||||||
* You can choose to use the default log receiver which saves all LOG calls to file, **or** you can choose to use your own custom made log receiver(s), **or** both, **or** as many sinks as you need.
|
* You can choose to use the default log receiver which saves all LOG calls to file, **or** you can choose to use your own custom made log receiver(s), **or** both, **or** as many sinks as you need.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### <a name="#conditional-logging">Conditional logging</a>
|
#### <a name="#conditional-logging">Conditional logging</a>
|
||||||
int less = 1; int more = 2
|
int less = 1; int more = 2
|
||||||
LOG_IF(INFO, (less<more)) <<"If [true], then this text will be logged";
|
LOG_IF(INFO, (less<more)) <<"If [true], then this text will be logged";
|
||||||
|
|
||||||
// or with printf-like syntax
|
// or with printf-like syntax
|
||||||
LOGF_IF(INFO, (less<more), "if %d<%d then this text will be logged", less,more);
|
LOGF_IF(INFO, (less<more), "if %d<%d then this text will be logged", less,more);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### <a name="design-by-contract">Design-by-Contract</a>
|
#### <a name="design-by-contract">Design-by-Contract</a>
|
||||||
*CHECK(false)* will trigger a "fatal" message. It will be logged, and then the
|
*CHECK(false)* will trigger a "fatal" message. It will be logged, and then the
|
||||||
application will exit.
|
application will exit.
|
||||||
|
|
||||||
```
|
```
|
||||||
CHECK(less != more); // not FATAL
|
CHECK(less != more); // not FATAL
|
||||||
CHECK(less > more) << "CHECK(false) triggers a FATAL message";
|
CHECK(less > more) << "CHECK(false) triggers a FATAL message";
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Detailed API documentation
|
### Detailed API documentation
|
||||||
Please look at [API.md](API.md) for detailed API documentation
|
Please look at [API.md](API.md) for detailed API documentation
|
||||||
|
|
||||||
|
|
||||||
## <a name="benefits-with-g3log">Benefits you get when using G3log</a>
|
## <a name="benefits-with-g3log">Benefits you get when using g3log</a>
|
||||||
1. Easy to use, clean syntax and a blazing fast logger.
|
1. Easy to use, clean syntax and a blazing fast logger.
|
||||||
|
|
||||||
2. All the slow log I/O disk access is done in a background thread. This ensures that the LOG caller can immediately continue with other tasks and do not have to wait for the LOG call to finish.
|
2. All the slow log I/O disk access is done in a background thread. This ensures that the LOG caller can immediately continue with other tasks and do not have to wait for the LOG call to finish.
|
||||||
|
|
||||||
3. G3log provides logging, Design-by-Contract [#CHECK], and flush of log to file at
|
3. G3log provides logging, Design-by-Contract [#CHECK], and flush of log to file at
|
||||||
shutdown. Buffered logs will be written to the sink before the application shuts down.
|
shutdown. Buffered logs will be written to the sink before the application shuts down.
|
||||||
|
|
||||||
4. It is thread safe, so using it from multiple threads is completely fine.
|
4. It is thread safe, so using it from multiple threads is completely fine.
|
||||||
|
|
||||||
5. It is *CRASH SAFE*. It will save the made logs to the sink before it shuts down.
|
5. It is *CRASH SAFE*. It will save the made logs to the sink before it shuts down.
|
||||||
The logger will catch certain fatal events *(Linux/OSX: signals, Windows: fatal OS exceptions and signals)* , so if your application crashes due to, say a segmentation fault, *SIGSEGV*, it will log and save the crash and all previously buffered log entries before exiting.
|
The logger will catch certain fatal events *(Linux/OSX: signals, Windows: fatal OS exceptions and signals)* , so if your application crashes due to, say a segmentation fault, *SIGSEGV*, it will log and save the crash and all previously buffered log entries before exiting.
|
||||||
|
|
||||||
|
|
||||||
6. It is cross platform. Tested and used by me or by clients on OSX, Windows, Ubuntu, CentOS
|
6. It is cross platform. Tested and used by me or by clients on OSX, Windows, Ubuntu, CentOS
|
||||||
|
|
||||||
7. G3log and G2log are used worldwide in commercial products as well as hobby projects. G2log was introduced in early 2011 and is now retired.
|
7. G3log and G2log are used worldwide in commercial products as well as hobby projects. G2log was introduced in early 2011 and is now retired.
|
||||||
|
|
||||||
8. The code is given for free as public domain. This gives the option to change, use, and do whatever with it, no strings attached.
|
8. The code is given for free as public domain. This gives the option to change, use, and do whatever with it, no strings attached.
|
||||||
|
|
||||||
9. *[g3log](https://github.com/KjellKod/g3log)* : is made to facilitate easy adding of custom log receivers. Its tested on at least the following platforms with **Linux**(Clang/gcc), **Windows** (mingw, visual studio) and **OSX**. My recommendation is to go with g3log if you have full C++14 support (C++11 support up to version: https://github.com/KjellKod/g3log/releases/tag/1.3.1).
|
9. *[g3log](https://github.com/KjellKod/g3log)* : is made to facilitate easy adding of custom log receivers. Its tested on at least the following platforms with **Linux**(Clang/gcc), **Windows** (mingw, visual studio) and **OSX**. My recommendation is to go with g3log if you have full C++14 support (C++11 support up to version: https://github.com/KjellKod/g3log/releases/tag/1.3.1).
|
||||||
|
|
||||||
|
|
||||||
## <a name="g3log-with-sinks">G3log with sinks</a>
|
## <a name="g3log-with-sinks">G3log with sinks</a>
|
||||||
[Sinks](http://en.wikipedia.org/wiki/Sink_(computing)) are receivers of LOG calls. G3log comes with a default sink (*the same as G3log uses*) that can be used to save log to file. A sink can be of *any* class type without restrictions as long as it can either receive a LOG message as a *std::string* **or** as a *g3::LogMessageMover*.
|
[Sinks](http://en.wikipedia.org/wiki/Sink_(computing)) are receivers of LOG calls. G3log comes with a default sink (*the same as g3log uses*) that can be used to save log to file. A sink can be of *any* class type without restrictions as long as it can either receive a LOG message as a *std::string* **or** as a *g3::LogMessageMover*.
|
||||||
|
|
||||||
The *std::string* comes pre-formatted. The *g3::LogMessageMover* is a wrapped struct that contains the raw data for custom handling in your own sink.
|
The *std::string* comes pre-formatted. The *g3::LogMessageMover* is a wrapped struct that contains the raw data for custom handling in your own sink.
|
||||||
|
|
||||||
A sink is *owned* by the G3log and is added to the logger inside a ```std::unique_ptr```. The sink can be called though its public API through a *handler* which will asynchronously forward the call to the receiving sink.
|
A sink is *owned* by the g3log and is added to the logger inside a ```std::unique_ptr```. The sink can be called though its public API through a *handler* which will asynchronously forward the call to the receiving sink.
|
||||||
|
|
||||||
It is <a name="crazy-simple">crazy simple to create a custom sink</a>. This example show what is needed to make a custom sink that is using custom log formatting but only using that
|
It is <a name="crazy-simple">crazy simple to create a custom sink</a>. This example show what is needed to make a custom sink that is using custom log formatting but only using that
|
||||||
for adding color to the default log formatting. The sink forwards the colored log to cout
|
for adding color to the default log formatting. The sink forwards the colored log to cout
|
||||||
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// in file Customsink.hpp
|
// in file Customsink.hpp
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <g3log/logmessage.hpp>
|
#include <g3log/logmessage.hpp>
|
||||||
|
|
||||||
struct CustomSink {
|
struct CustomSink {
|
||||||
|
|
||||||
// Linux xterm color
|
// Linux xterm color
|
||||||
// http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
|
// http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
|
||||||
enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97};
|
enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97};
|
||||||
|
|
||||||
FG_Color GetColor(const LEVELS level) const {
|
FG_Color GetColor(const LEVELS level) const {
|
||||||
if (level.value == WARNING.value) { return YELLOW; }
|
if (level.value == WARNING.value) { return YELLOW; }
|
||||||
if (level.value == DEBUG.value) { return GREEN; }
|
if (level.value == DEBUG.value) { return GREEN; }
|
||||||
if (g3::internal::wasFatal(level)) { return RED; }
|
if (g3::internal::wasFatal(level)) { return RED; }
|
||||||
|
|
||||||
return WHITE;
|
return WHITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReceiveLogMessage(g3::LogMessageMover logEntry) {
|
void ReceiveLogMessage(g3::LogMessageMover logEntry) {
|
||||||
auto level = logEntry.get()._level;
|
auto level = logEntry.get()._level;
|
||||||
auto color = GetColor(level);
|
auto color = GetColor(level);
|
||||||
|
|
||||||
std::cout << "\033[" << color << "m"
|
std::cout << "\033[" << color << "m"
|
||||||
<< logEntry.get().toString() << "\033[m" << std::endl;
|
<< logEntry.get().toString() << "\033[m" << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// in main.cpp, main() function
|
// in main.cpp, main() function
|
||||||
|
|
||||||
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
|
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
|
||||||
&CustomSink::ReceiveLogMessage);
|
&CustomSink::ReceiveLogMessage);
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Adding and Removing Sinks
|
## Adding and Removing Sinks
|
||||||
You can safely remove and add sinks during the running of your program.
|
You can safely remove and add sinks during the running of your program.
|
||||||
|
|
||||||
**Keep in mind**
|
**Keep in mind**
|
||||||
|
|
||||||
- *Initialization of the logger should happen before you have started any other threads that may call the logger.*
|
- *Initialization of the logger should happen before you have started any other threads that may call the logger.*
|
||||||
- *Destruction of the logger (RAII concept) should happen AFTER shutdown of other threads that are calling the logger.*
|
- *Destruction of the logger (RAII concept) should happen AFTER shutdown of other threads that are calling the logger.*
|
||||||
|
|
||||||
**Adding Sinks**
|
**Adding Sinks**
|
||||||
```cpp
|
```cpp
|
||||||
auto sinkHandle1 = logworker->addSink(std::make_unique<CustomSink>(),
|
auto sinkHandle1 = logworker->addSink(std::make_unique<CustomSink>(),
|
||||||
&CustomSink::ReceiveLogMessage);
|
&CustomSink::ReceiveLogMessage);
|
||||||
auto sinkHandle2 = logworker->addDefaultLogger(argv[0],
|
auto sinkHandle2 = logworker->addDefaultLogger(argv[0],
|
||||||
path_to_log_file);
|
path_to_log_file);
|
||||||
logworker->removeSink(std::move(sinkHandle1)); // this will in a thread-safe manner remove the sinkHandle1
|
logworker->removeSink(std::move(sinkHandle1)); // this will in a thread-safe manner remove the sinkHandle1
|
||||||
logworker->removeAllSinks(); // this will in a thread-safe manner remove any sinks.
|
logworker->removeAllSinks(); // this will in a thread-safe manner remove any sinks.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
**More sinks** can be found in the repository **[github.com/KjellKod/g3sinks](https://github.com/KjellKod/g3sinks)**.
|
**More sinks** can be found in the repository **[github.com/KjellKod/g3sinks](https://github.com/KjellKod/g3sinks)**.
|
||||||
|
|
||||||
|
|
||||||
## <a name="code-examples">Code Examples</a>
|
## <a name="code-examples">Code Examples</a>
|
||||||
Example usage where a <a name="custom-sink">custom sink</a> is added. A function is called though the sink handler to the actual sink object.
|
Example usage where a <a name="custom-sink">custom sink</a> is added. A function is called though the sink handler to the actual sink object.
|
||||||
```cpp
|
```cpp
|
||||||
// main.cpp
|
// main.cpp
|
||||||
#include <g3log/g3log.hpp>
|
#include <g3log/g3log.hpp>
|
||||||
#include <g3log/logworker.hpp>
|
#include <g3log/logworker.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "CustomSink.h"
|
#include "CustomSink.h"
|
||||||
|
|
||||||
int main(int argc, char**argv) {
|
int main(int argc, char**argv) {
|
||||||
using namespace g3;
|
using namespace g3;
|
||||||
std::unique_ptr<LogWorker> logworker{ LogWorker::createLogWorker() };
|
std::unique_ptr<LogWorker> logworker{ LogWorker::createLogWorker() };
|
||||||
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
|
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
|
||||||
&CustomSink::ReceiveLogMessage);
|
&CustomSink::ReceiveLogMessage);
|
||||||
|
|
||||||
// initialize the logger before it can receive LOG calls
|
// initialize the logger before it can receive LOG calls
|
||||||
initializeLogging(logworker.get());
|
initializeLogging(logworker.get());
|
||||||
LOG(WARNING) << "This log call, may or may not happend before"
|
LOG(WARNING) << "This log call, may or may not happend before"
|
||||||
<< "the sinkHandle->call below";
|
<< "the sinkHandle->call below";
|
||||||
|
|
||||||
|
|
||||||
// You can call in a thread safe manner public functions on your sink
|
// You can call in a thread safe manner public functions on your sink
|
||||||
// The call is asynchronously executed on your custom sink.
|
// The call is asynchronously executed on your custom sink.
|
||||||
std::future<void> received = sinkHandle->call(&CustomSink::Foo,
|
std::future<void> received = sinkHandle->call(&CustomSink::Foo,
|
||||||
param1, param2);
|
param1, param2);
|
||||||
|
|
||||||
// If the LogWorker is initialized then at scope exit the g3::internal::shutDownLogging() will be called.
|
// If the LogWorker is initialized then at scope exit the g3::internal::shutDownLogging() will be called.
|
||||||
// This is important since it protects from LOG calls from static or other entities that will go out of
|
// This is important since it protects from LOG calls from static or other entities that will go out of
|
||||||
// scope at a later time.
|
// scope at a later time.
|
||||||
//
|
//
|
||||||
// It can also be called manually:
|
// It can also be called manually:
|
||||||
g3::internal::shutDownLogging();
|
g3::internal::shutDownLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// some_file.cpp : To show how easy it is to get the logger to work
|
// some_file.cpp : To show how easy it is to get the logger to work
|
||||||
// in other parts of your software
|
// in other parts of your software
|
||||||
|
|
||||||
#include <g3log/g3log.hpp>
|
#include <g3log/g3log.hpp>
|
||||||
|
|
||||||
void SomeFunction() {
|
void SomeFunction() {
|
||||||
...
|
...
|
||||||
LOG(INFO) << "Hello World";
|
LOG(INFO) << "Hello World";
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Example usage where a the <a name="default-file-logger">default file logger</a> is used **and** a custom sink is added
|
Example usage where a the <a name="default-file-logger">default file logger</a> is used **and** a custom sink is added
|
||||||
```cpp
|
```cpp
|
||||||
// main.cpp
|
// main.cpp
|
||||||
#include <g3log/g3log.hpp>
|
#include <g3log/g3log.hpp>
|
||||||
#include <g3log/logworker.hpp>
|
#include <g3log/logworker.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "CustomSink.h"
|
#include "CustomSink.h"
|
||||||
|
|
||||||
int main(int argc, char**argv) {
|
int main(int argc, char**argv) {
|
||||||
using namespace g3;
|
using namespace g3;
|
||||||
auto worker = LogWorker::createLogWorker();
|
auto worker = LogWorker::createLogWorker();
|
||||||
auto defaultHandler = worker->addDefaultLogger(argv[0],
|
auto defaultHandler = worker->addDefaultLogger(argv[0],
|
||||||
path_to_log_file);
|
path_to_log_file);
|
||||||
|
|
||||||
// logger is initialized
|
// logger is initialized
|
||||||
g3::initializeLogging(worker.get());
|
g3::initializeLogging(worker.get());
|
||||||
|
|
||||||
LOG(DEBUG) << "Make log call, then add another sink";
|
LOG(DEBUG) << "Make log call, then add another sink";
|
||||||
|
|
||||||
worker->addSink(std::make_unique<CustomSink>(),
|
worker->addSink(std::make_unique<CustomSink>(),
|
||||||
&CustomSink::ReceiveLogMessage);
|
&CustomSink::ReceiveLogMessage);
|
||||||
|
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[introduction](index.md) | [**detailed information**](g3log.md) | [Configure & Build](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)
|
[introduction](index.md) | [**detailed information**](g3log.md) | [Configure & Build](building.md) | [API description](API.md) | [Custom log formatting](API_custom_formatting.md)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
site_name: G3log, an asynchronous "crash-safe" logger
|
site_name: G3log, an asynchronous "crash-safe" logger
|
||||||
site_author: 'Kjell Hedström'
|
site_author: 'Kjell Hedström'
|
||||||
docs_dir: docs/
|
|
||||||
repo_name: 'KjellKod/g3log'
|
repo_name: 'KjellKod/g3log'
|
||||||
repo_url: 'https://github.com/KjellKod/g3log'
|
repo_url: 'https://github.com/KjellKod/g3log'
|
||||||
theme:
|
theme:
|
||||||
|
Loading…
Reference in New Issue
Block a user