Commit b7477d6b authored by Philippe Gaussier's avatar Philippe Gaussier
Browse files

Suppress the files of the lib loguru.

parent 6dc0cdc7
Pipeline #1266 failed with stage
in 3 minutes and 15 seconds
# Loguru: a lightweight and flexible C++ logging library.
[![Build status](https://ci.appveyor.com/api/projects/status/hret4rx3xakjs7j4?svg=true)](https://ci.appveyor.com/project/emilk/loguru)
## At a glance
![Loguru terminal output](docs/terminal_colors.png)
## Documentation
Documentation can be found at https://emilk.github.io/loguru/index.html.
## License
This software is in the public domain. Where that dedication is not recognized, you are granted a perpetual, irrevocable license to copy, modify and distribute it as you see fit.
That being said, I would appreciate credit!
If you find Loguru useful, tweet me at @ernerfeldt mail me at emil.ernerfeldt@gmail.com.
## Why another logging library?
I have yet to come across a nice, light-weight logging library for C++ that does everything I want. So I made one!
In particular, I want logging that produces logs that are both human-readable and easily grep:ed. I also want to be able to hook into the logging process to print some of the more severe messages on-screen in my app (for dev-purposes).
## Features:
* Simple integration
* Just two files: `loguru.hpp` and `loguru.cpp`.
* Either build and link `loguru.cpp` or just `#include <loguru.cpp>` in one of your own .cpp files.
* Small, simple library.
* Small header with no `#include`s for **fast compile times** (see separate heading).
* No dependencies.
* Cross-platform
* Flexible:
* User can install callbacks for logging (e.g. to draw log messages on screen in a game).
* User can install callbacks for fatal error (e.g. to pause an attached debugger or throw an exception).
* Support multiple file outputs, either trunc or append:
* e.g. a logfile with just the latest run at low verbosity (high readability).
* e.g. a full logfile at highest verbosity which is appended to on every run.
* Full featured:
* Verbosity levels.
* Supports assertions: `CHECK_F(fp != nullptr, "Failed to open '%s'", filename)`
* Supports abort: `ABORT_F("Something went wrong, debug value is %d", value)`.
* Stack traces printed on abort.
* Stack traces are cleaned up somewhat.
* Before cleanup: `some_function_name(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)`
* After cleanup: `some_function_name(std::vector<std::string> const&)`
* Stack traces are printed [the right way](http://yellerapp.com/posts/2015-01-22-upside-down-stacktraces.html):
* Chronological order with the most relevant at the end.
* (most) signals writes stack traces.
* Fast:
- When configured in unbuffered mode (loguru::g_flush_interval_ms = 0):
+ 6-8 us when logging to stderr + file (rMBP + SSD + Clang).
+ About 25%-75% faster than GLOG on my MacBook Pro (Clang).
+ About the same as GLOG on my Linux Desktop (GCC).
- With loguru::g_flush_interval_ms set to ~100 ms:
+ 3-5 us when logging to stderr + file (rMBP + SSD + Clang).
+ About twice as fast as GLOG.
* Drop-in replacement for most of GLOG (except for setup code).
* Choose between using printf-style or std::cout-style formatting.
* Compile-time checked printf-formating (on supported compilers).
* Support for [fmtlib](https://github.com/fmtlib/fmt) formatting.
* Add `#define LOGURU_USE_FMTLIB 1`, before including `loguru.hpp`
* You also need to set up the `fmtlib` include directory for building as well as linking against `fmtlib`, alternatively use the `FMT_HEADER_ONLY` preprocessor definition.
* Assertion failures are marked with `noreturn` for the benefit of the static analyzer and optimizer.
* All logging also written to stderr.
* With colors on supported terminals.
* Thread-safe.
* Can be configured to either:
* Flush every `loguru::g_flush_interval_ms` in a background thread
* Flushes output on each call so you won't miss anything even on hard crashes (and still faster than buffered GLOG!).
* Prefixes each log line with:
* Date and time to millisecond precision.
* Application uptime to millisecond precision.
* Thread name or id (you can set the name with `loguru::set_thread_name`).
* File and line.
* Log level.
* Indentation (see *Scopes*).
* Error context:
* Catch the values of local variables and print them only on a crash (see *Error context*).
* Scopes (see *Scopes*).
* grep:able logs:
* Each line has all the info you need (e.g. date).
* You can easily filter out high verbosity levels after the fact.
## Compiling
Just include <loguru.hpp> where you want to use Loguru.
Then either compile and link with `loguru.cpp` or in one .cpp file: `#include <loguru.cpp>`
Make sure you compile with `-std=c++11 -lpthread -ldl` on relevant environments.
## Usage
``` C++
#include <loguru.hpp>
// Optional, but useful to time-stamp the start of the log.
// Will also detect verbosity level on command line as -v.
loguru::init(argc, argv);
// Put every log message in "everything.log":
loguru::add_file("everything.log", loguru::Append, loguru::Verbosity_MAX);
// Only log INFO, WARNING, ERROR and FATAL to "latest_readable.log":
loguru::add_file("latest_readable.log", loguru::Truncate, loguru::Verbosity_INFO);
// Only show most relevant things on stderr:
loguru::g_stderr_verbosity = 1;
LOG_SCOPE_F(INFO, "Will indent all log messages within this scope.");
LOG_F(INFO, "I'm hungry for some %.3f!", 3.14159);
LOG_F(2, "Will only show if verbosity is 2 or higher");
VLOG_F(get_log_level(), "Use vlog for dynamic log level (integer in the range 0-9, inclusive)");
LOG_IF_F(ERROR, badness, "Will only show if badness happens");
auto fp = fopen(filename, "r");
CHECK_F(fp != nullptr, "Failed to open file '%s'", filename);
CHECK_GT_F(length, 0); // Will print the value of `length` on failure.
CHECK_EQ_F(a, b, "You can also supply a custom message, like to print something: %d", a + b);
// Each function also comes with a version prefixed with D for Debug:
DCHECK_F(expensive_check(x)); // Only checked #if !NDEBUG
DLOG_F(INFO, "Only written in debug-builds");
// Turn off writing to stderr:
loguru::g_stderr_verbosity = loguru::Verbosity_OFF;
// Turn off writing err/warn in red:
loguru::g_colorlogtostderr = false;
// Throw exceptions instead of aborting on CHECK fails:
loguru::set_fatal_handler([](const loguru::Message& message){
throw std::runtime_error(std::string(message.prefix) + message.message);
});
```
If you prefer logging with streams:
``` C++
#define LOGURU_WITH_STREAMS 1
#include <loguru.hpp>
...
LOG_S(INFO) << "Look at my custom object: " << a.cross(b);
CHECK_EQ_S(pi, 3.14) << "Maybe it is closer to " << M_PI;
```
For more info, see [the official documentation](https://emilk.github.io/loguru/index.html).
## Grep:able logs
``` bash
# Only show warnings, errors and fatal messages:
cat logfile.txt | egrep "[^0-9]\|"
# Ignore verbosity-levels 4 and above:
cat logfile.txt | egrep "[^4-9]\|"
# Only show verbosity-level 6:
cat logfile.txt | egrep "6\|"
# Only show messages from the main thread:
cat logfile.txt | egrep "\[main thread \]"
```
## No includes in loguru.hpp
I abhor logging libraries that `#include`'s everything from `iostream` to `windows.h` into every compilation unit in your project. Logging should be frequent in your source code, and thus as lightweight as possible. Loguru's header has *no #includes*. This means it will not slow down the compilation of your project.
In a test of a medium-sized project, including `loguru.hpp` instead of `glog/logging.hpp` everywhere gave about 10% speedup in compilation times.
Note, however, that this gives you the bare-bones version of Loguru with printf-style logging. If you want `std::ostream` style logging (or GLOG functionality) you need to `#define LOGURU_WITH_STREAMS 1` before `#include <loguru.hpp>`, and that will make `loguru.hpp` include `<sstream>`. No away around it!
## Scopes
The library supports scopes for indenting the log-file. Here's an example:
``` C++
int main(int argc, char* argv[])
{
loguru::init(argc, argv);
LOG_SCOPE_FUNCTION(INFO);
LOG_F(INFO, "Doing some stuff...");
for (int i=0; i<2; ++i) {
VLOG_SCOPE_F(1, "Iteration %d", i);
auto result = some_expensive_operation();
LOG_IF_F(WARNING, result == BAD, "Bad result");
}
LOG_F(INFO, "Time to go!");
return 0;
}
```
This will output:
```
loguru.cpp:184 0| arguments: ./loguru_test test -v1
loguru.cpp:185 0| Verbosity level: 1
loguru.cpp:186 0| -----------------------------------
loguru_test.cpp:108 0| { int main_test(int, char **)
loguru_test.cpp:109 0| . Doing some stuff...
loguru_test.cpp:111 1| . { Iteration 0
loguru_test.cpp:111 1| . } 0.133 s: Iteration 0
loguru_test.cpp:111 1| . { Iteration 1
loguru_test.cpp:113 0| . . Bad result
loguru_test.cpp:111 1| . } 0.134 s: Iteration 1
loguru_test.cpp:115 0| . Time to go!
loguru_test.cpp:108 0| } 0.267 s: int main_test(int, char **)
```
# `ERROR_CONTEXT`
You can also optionally log things ONLY if there is a crash. This is a very useful feature:
```
void process_file(const char* filename)
{
ERROR_CONTEXT("filename", filename);
parse_file(filename); // Only if this crashes will filename be logged.
}
```
## Streams vs printf
Some logging libraries only supports stream style logging, not printf-style. This means that what in Loguru is:
``` C++
LOG_F(INFO, "Some float: %+05.3f", number);
```
in Glog becomes something along the lines of:
``` C++
LOG(INFO) << "Some float: " << std::setfill('0') << std::setw(5) << std::setprecision(3) << number;
```
Loguru allows you to use whatever style you prefer.
version: 0.1.{build}-{branch}
pull_requests:
do_not_increment_build_number: true
image:
- Ubuntu
- Visual Studio 2017
# loguru is header-only
build: off
test_script: cmake -P test/appveyor.cmake
This diff is collapsed.
cmake_minimum_required(VERSION 2.8)
project(glog_bench)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE)
MESSAGE(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
add_compile_options(-std=c++11 -Werror -Wall -Wextra)
file(GLOB source
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
)
# ------------------------------------------------------
# GFLAGS
find_library(GFLAGS_LIB NAMES "gflags" PATHS
${GFLAGS_ROOT}/lib
${GFLAGS_ROOT}/Lib)
if (MSVC)
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h PATHS ${GFLAGS_ROOT}/Include)
set(GFLAGS_LIB_DIR ${GFLAGS_ROOT}/Lib)
else()
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h PATHS
${GFLAGS_ROOT}/include)
set(GFLAGS_LIB_DIR ${GFLAGS_ROOT}/lib)
endif()
mark_as_advanced(
GFLAGS_INCLUDE_DIR
GFLAGS_LIB
)
# ------------------------------------------------------
# GLOG
find_library(GLOG_LIB NAMES "glog" libglog PATHS
${GLOG_ROOT})
if (MSVC)
find_path(GLOG_INCLUDE_DIR glog/logging.h PATHS ${GLOG_ROOT})
set(GLOG_LIB_DIR ${GLOG_ROOT})
add_definitions(-DUSE_OWN_CHECK)
else()
find_path(GLOG_INCLUDE_DIR glog/logging.h PATHS
${GLOG_ROOT}/include)
set(GLOG_LIB_DIR ${GLOG_ROOT}/lib)
endif()
add_definitions(-DGLOG_NO_ABBREVIATED_SEVERITIES=1)
mark_as_advanced(
GLOG_INCLUDE_DIR
GLOG_LIB
)
# ------------------------------------------------------
add_executable(glog_bench ${source})
include_directories(
${GFLAGS_INCLUDE_DIR}
${GLOG_INCLUDE_DIR}
)
target_link_libraries(glog_bench
${GFLAGS_LIB}
${GLOG_LIB}
)
#!/bin/bash
set -e # Fail on error
ROOT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
cd "$ROOT_DIR"
mkdir -p build
cd build
cmake ..
make
./glog_bench $@ 2>/dev/null
#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <glog/logging.h>
#include <glog/raw_logging.h>
const size_t kNumIterations = 50 * 1000;
const size_t kNumRuns = 10;
const double kPi = 3.1415926535897932384626433;
static long long now_ns()
{
using namespace std::chrono;
return duration_cast<nanoseconds>(high_resolution_clock::now().time_since_epoch()).count();
}
template<typename Function>
double time_sec(const Function& function)
{
auto start_ns = now_ns();
function();
return (now_ns() - start_ns) * 1e-9;
}
template<typename Function>
void bench(const std::string& name, const Function& function)
{
function(); // Warm-up
printf("%-30s ", name.c_str());
fflush(stdout);
std::vector<double> times;
double sum = 0;
for (size_t i = 0; i < kNumRuns; ++i)
{
times.push_back(time_sec(function) / kNumIterations);
sum += times.back();
}
double mean = sum / kNumRuns;
double std_dev_sum = 0;
for (double time : times) {
std_dev_sum += (time - mean) * (time - mean);
}
double variance = std::sqrt(std_dev_sum / kNumRuns);
printf("%6.3f +- %.3f us per call\n", mean * 1e6, variance * 1e6);
fflush(stdout);
}
// ----------------------------------------------------------------------------
void stream_strings()
{
for (size_t i = 0; i < kNumIterations; ++i) {
LOG(WARNING) << "Some long, complex message.";
}
google::FlushLogFiles(google::GLOG_INFO);
}
void stream_float()
{
for (size_t i = 0; i < kNumIterations; ++i) {
LOG(WARNING) << std::setfill('0') << std::setw(6) << std::setprecision(3) << kPi;
}
google::FlushLogFiles(google::GLOG_INFO);
}
void raw_string_float()
{
for (size_t i = 0; i < kNumIterations; ++i) {
RAW_LOG(WARNING, "Some long, complex message.");
}
google::FlushLogFiles(google::GLOG_INFO);
}
int main(int argc, char* argv[])
{
FLAGS_alsologtostderr = true;
google::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
bench("LOG(WARNING) << string (buffered):", stream_strings);
bench("LOG(WARNING) << float (buffered):", stream_float);
FLAGS_logbufsecs = 0; // Flush all output in realtime
bench("LOG(WARNING) << string (unbuffered):", stream_strings);
bench("LOG(WARNING) << float (unbuffered):", stream_float);
}
cmake_minimum_required(VERSION 2.8)
project(glog_example)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE)
MESSAGE(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
add_compile_options(-std=c++11 -Werror -Wall -Wextra)
file(GLOB source
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
)
# ------------------------------------------------------
# GFLAGS
find_library(GFLAGS_LIB NAMES "gflags" PATHS
${GFLAGS_ROOT}/lib
${GFLAGS_ROOT}/Lib)
if (MSVC)
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h PATHS ${GFLAGS_ROOT}/Include)
set(GFLAGS_LIB_DIR ${GFLAGS_ROOT}/Lib)
else()
find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h PATHS
${GFLAGS_ROOT}/include)
set(GFLAGS_LIB_DIR ${GFLAGS_ROOT}/lib)
endif()
mark_as_advanced(
GFLAGS_INCLUDE_DIR
GFLAGS_LIB
)
# ------------------------------------------------------
# GLOG
find_library(GLOG_LIB NAMES "glog" libglog PATHS
${GLOG_ROOT})
if (MSVC)
find_path(GLOG_INCLUDE_DIR glog/logging.h PATHS ${GLOG_ROOT})
set(GLOG_LIB_DIR ${GLOG_ROOT})
add_definitions(-DUSE_OWN_CHECK)
else()
find_path(GLOG_INCLUDE_DIR glog/logging.h PATHS
${GLOG_ROOT}/include)
set(GLOG_LIB_DIR ${GLOG_ROOT}/lib)
endif()
add_definitions(-DGLOG_NO_ABBREVIATED_SEVERITIES=1)
mark_as_advanced(
GLOG_INCLUDE_DIR
GLOG_LIB
)
# ------------------------------------------------------
add_executable(glog_example ${source})
include_directories(
${GFLAGS_INCLUDE_DIR}
${GLOG_INCLUDE_DIR}
)
target_link_libraries(glog_example
${GFLAGS_LIB}
${GLOG_LIB}
)
#!/bin/bash
set -e # Fail on error
ROOT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
cd "$ROOT_DIR"
mkdir -p build
cd build
cmake ..
make
./glog_example $@
#include <chrono>
#include <thread>
#include <glog/logging.h>
inline void sleep_ms(int ms)
{
VLOG(2) << "Sleeping for " << ms << " ms";
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
inline void complex_calculation()
{
LOG(INFO) << "complex_calculation started";
LOG(INFO) << "Starting time machine...";
sleep_ms(200);
LOG(WARNING) << "The flux capacitor is not getting enough power!";
sleep_ms(400);
LOG(INFO) << "Lighting strike!";
VLOG(1) << "Found 1.21 gigawatts...";
sleep_ms(400);
std::thread([](){
LOG(ERROR) << "We ended up in 1985!";
}).join();
LOG(INFO) << "complex_calculation stopped";
}
#include <iostream>
#include "glog_example.hpp"
int main(int argc, char* argv[])
{
FLAGS_alsologtostderr = true;
FLAGS_colorlogtostderr = true;
google::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
LOG(INFO) << "Hello from main.cpp!";
complex_calculation();
LOG(INFO) << "main function about to end!";
}
This diff is collapsed.
This diff is collapsed.
cmake_minimum_required(VERSION 2.8)
project(loguru_bench)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE)
MESSAGE(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -Wextra")
file(GLOB source
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
)
add_executable(loguru_bench ${source})
find_package(Threads)
target_link_libraries(loguru_bench ${CMAKE_THREAD_LIBS_INIT}) # For pthreads
target_link_libraries(loguru_bench dl) # For ldl
#!/bin/bash
set -e # Fail on error
ROOT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
cd "$ROOT_DIR"
mkdir -p build
cd build
cmake ..
make
./loguru_bench $@ 2>/dev/null
#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>
#define LOGURU_WITH_STREAMS 1
#define LOGURU_REDEFINE_ASSERT 1
#include "../loguru.cpp"