• Stars
    star
    15
  • Rank 1,325,546 (Top 27 %)
  • Language
    C++
  • License
    MIT License
  • Created over 7 years ago
  • Updated about 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Cross platform multi-process C++ logging system

uberlog

uberlog is a cross platform C++ logging system that is:

  1. Small
  2. Fast
  3. Robust
  4. Runs on Linux, Windows, OSX
  5. MIT License

Small

Two headers, and three source files. Only 2399 lines of code, excluding tests.

Fast

Logs are written to a shared memory ring buffer. Your program only stalls if the queue is full, which only happens when the writer cannot keep up with the amount of log messages. Under such circumstances, you generally have worse problems (ie unsustainable system load).

By using a multi-process architecture, the number of syscalls issued by uberlog is extremely low. This is of particular relevance on a CPU/OS with Meltdown mitigations, particularly Kernel Page Table Isolation.

Robust

A child process is spawned, which takes care of writing the log messages to a file. Even if the main process faults immediately after writing a log message, that last message (and all the messages before it) will be written into the log file, because the log writer process will drain the queue, and then exit once it notices that the main process has died.

Uberlog includes log rolling. You control the maximum size of the log files, and how many historic log files are kept around.

Uberlog includes type safe formatting that is compatible with printf. See tsf for details on how that works.

Example

#include <uberlog.h>

void example()
{
	uberlog::Logger log;
	log.SetArchiveSettings(50 * 1024 * 1024, 3);    // 3 file history, 50 MB each
	log.SetLevel(uberlog::Level::Info);             // emit logs of level Info or higher
	log.Open("/var/log/mylog");
	log.Info("Starting up");
	log.Warn("Type safe printf %v", "formatting");
}

Extending

The functions built into Logger format their output like this:

Time in server's time zone  Level  Thread   Message
             |                |      |        |
2016-11-05T14:28:36.584+0200 [I] 00002c78 The log message

If you want to change that, then you can implement your own logger on top of uberlog::Logger - either by deriving a class from it, or encapsulating it inside your own class. You can then use the LogRaw function of Logger to emit messages in whatever format you choose.

Note that you can disable the output of the time in the log message, by setting IncludeDate = false.

Benchmarks

These benchmarks are on an i7-6700K

OS Latency Throughput
Windows 200 ns 350 MB/s
Linux 280 ns 465 MB/s

Those numbers are for a formatted log message that is around 200 bytes long. The ring buffer copy is around 40 ns, and the buildup of the date string is 130 ns. The remainder is the formatting of the log message. The ring buffer size affects the maximum log throughput rate, but the latency is independent of the ring buffer size.

At a low rate of messages (a few hundred per second), latency is more important that throughput. To be clear, latency here is the time taken inside your program to produce the log message and add it to the ring buffer. There is so much headroom in throughput, that you've probably got worse problems if you're hitting those limits.

To put this all into context, let's consider the performance that you get from a naive logging system that you can easily roll yourself, which simply issues an OS level write call for every log message. What kind of performance do you get from such a system, and how does it compare to uberlog?

To start with, a kernel call to write 100 bytes to a file is around 1500 ns. Now let's assume that you don't put much effort into optimizing your formatting function, or your date string generation, and you end up with another 1000 ns for the generation of the final log string. Add those together, and you get about 2500 ns per log message.

What does this mean for a typical application? Let's say you're writing 100 log messages per second. With our hypothetical naive logging system, that amounts to 0.25 milliseconds per second spent logging, which is 0.025% of your time. If we crank our throughput up to 1000 messages per second, our naive system is spending 0.25% of total time, just logging, which is still a pretty small number. At 100000 log messages per second, we start to see some real overhead, with 25% of our time spent just logging. By using uberlog, that overhead drops to just 2%.

Uberlog takes pains to make all phases of the log write fast, from the type safe format, to the caching of the date string, to the output into the ring buffer. That is how we're able to achieve a 10x speedup over a naive system.

When you look at the number above, it becomes quite clear that unless you're outputting many thousands of log messages per second, a naive solution is just fine. But if you want the best, you've come to the right place!

[2018 UPDATE]

Now that the Meltdown/Spectre bugs have surfaced, the uberlog architecture is more relevant, in terms of performance. I haven't yet taken the time to measure this, but it's clear from the research out there that it is good to avoid syscalls where possible (especially due to KPTI), and uberlog really shines in that respect.

More Repositories

1

authaus

A (relatively) simple Authentication and Authorization system
Go
30
star
2

flatbush

C++ port of https://github.com/mourner/flatbush
C++
18
star
3

utfz

Tiny C++ UTF-8 library - safe, no exceptions
C++
7
star
4

tsf

Type safe printf-compatible C++ library
C++
6
star
5

picolor.js

JavaScript color picker controls optimized for picking map colors
TypeScript
5
star
6

mapnik-windows

Prebuilt Mapnik binaries for Windows
C++
4
star
7

SwiftShaderBinaries

Precompiled SwiftShader binaries for Windows and Linux
4
star
8

scheduler

Task scheduler
Go
2
star
9

nf

Not a Framework for Go HTTP services
Go
2
star
10

htmlrender

Node express/puppeteer server that receives HTML, and returns PDF/PNG
JavaScript
2
star
11

httpbridge

A small C++ library for implementing an HTTP2 endpoint
C++
2
star
12

imqsauth

IMQS Authentication
Go
1
star
13

augmented

Augmented Reality Viewer
Java
1
star
14

InternalTimeTracker

System to track internal projects and time spent on them
Go
1
star
15

argparse

Single-file command line argument parser for C++11
C++
1
star
16

goscripts

A tiny Go package to aid in the creation of shell-script-like Go programs
Go
1
star
17

gowinsvc

Parts of the greater golang.org/x/sys package that allows the creation of windows services.
Go
1
star
18

maps-windows-deps

Source code and binaries for the Windows build of the IMQS Maps project
C
1
star
19

cli

Go helpers for building command-line applications
Go
1
star
20

simplexml

Copy of keylewolf repo tghat was deleted from github.
Go
1
star
21

cpp-forensics

C++ crash dump server
Python
1
star
22

Omicron

Omicron social networking GIS
OpenEdge ABL
1
star
23

CNN-Image-Label-Generator

Generates label files for images which are used for training. This one is specific for YOLO , but could likely be adapted for other image detection convolutional neural network frameworks.
C#
1
star
24

document-map-tool

A tool to retrieve document data from MongoDB and insert a translated representation into PostgreSQL.
Go
1
star