Skip to content

Commit

Permalink
Merge pull request #1 from ess-dmsc/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
SkyToGround authored Feb 24, 2017
2 parents cefeaf3 + d315a07 commit d3e559c
Show file tree
Hide file tree
Showing 17 changed files with 573 additions and 72 deletions.
158 changes: 106 additions & 52 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -1,128 +1,113 @@
# *dm-graylog-logger* examples
Instructions on how to install the C++ library dm-graylog-logger can be found on the [repository page](https://bitbucket.org/europeanspallationsource/dm-graylog-logger). The intent of this page is to give you examples on how the library can be used and extended. Other than the examples shown here, the code should be used as a reference.
# *graylog-logger* examples
Instructions on how to install the C++ library *graylog-logger* can be found on the [repository page](https://github.com/ess-dmsc/graylog-logger). The intent of this document is to give you examples on how the library can be used and extended. There is currently no code documentation except for the examples given here. For more information on implementation and interfaces see the header and implementation files. Most of the relevant interface information can be found in the header files `graylog_logger/Log.hpp` and `graylog_logger/LogUtil.hpp`.

## Basic example
By default, the library will log messages to console and Graylog server on localhost port 12201 (if available).
By default, the library will log messages to console.

```c++
#include <thread>
#include <chrono>
#include <graylog_logger/Log.hpp>

int main() {
Log::Msg(Severity::Warning, "Some message.");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```
The 100 *ms* delay has been added in order for the logging system to have time to actually write something before the application exists. The compiled application will print the following to console:
The compiled application will (should) print the following to console:

```
WARNING: Some message.
```

The following line will be written to the file `messages.log`:

```
2017-01-02 18:12:04 (CI0011840) WARNING: Some message.
```

Finally, a message will also be sent to the Graylog server listening on localhost port 12201.

## Printing only to console
In order to set-up the library to only print to console, all other interfaces have to be removed and a new console interface has to be added:
## Write log messages to file
In order to set-up the library to write messages to file, a file writer has to be added.

```c++
#include <thread>
#include <chrono>
#include <graylog_logger/Log.hpp>
#include <graylog_logger/ConsoleInterface.hpp>
#include <graylog_logger/FileInterface.hpp>

int main() {
Log::RemoveAllHandlers();
Log::AddLogHandler(new ConsoleInterface());
Log::AddLogHandler(new FileInterface("new_log_file.log"));
Log::Msg(Severity::Error, "This is an error.");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

This, of course, prints the following to console:
The `sleep_for()` function is added in order to give the file writing thread time to actually write the message before the application exits. The resulting file output should be similar to the following:

```
ERROR: This is an error.
2017-01-02 18:29:20 (CI0011840) ERROR: This is an error.
```

## Use another file name
As the code is currently set-up to immediatly create a file logging interface on run, the file `messages.log` will be created regardless. However in order to use another file name when writing the log messages, use the following code:
## Send messages to a Graylog server
To use the library for its original purpose, a Graylog server interface has to be added. This can be done as follows:

```c++
#include <thread>
#include <chrono>
#include <graylog_logger/Log.hpp>
#include <graylog_logger/FileInterface.hpp>
#include <graylog_logger/GraylogInterface.hpp>

int main() {
Log::RemoveAllHandlers();
Log::AddLogHandler(new FileInterface("new_log_file.log"));
Log::Msg(Severity::Warning, "New file warning.");
Log::AddLogHandler(new GraylogInterface("somehost.com", 12201));
Log::Msg(Severity::Error, "This message will be sent to a Graylog server.");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

This will output the following line to the file `new_log_file.log`.

```
2017-01-02 18:29:20 (CI0011840) WARNING: New file warning.
```
As the default file handler has not been removed this will send a message to console as well as to the Graylog server on "somehost.com".

## Send messages to another Graylog server
It is possible to send log messages to multiple Graylog servers (or files for that matter) at the same time:
## Stop writing to console
In order to prevent the logger from writing messages to (e.g.) console but still write to file (or Graylog server), existing log handlers must be removed using the `Log::RemoveAllHandlers()` function before adding the log handlers you do want to use.

```c++
#include <thread>
#include <chrono>
#include <graylog_logger/Log.hpp>
#include <graylog_logger/FileInterface.hpp>
#include <graylog_logger/GraylogInterface.hpp>

int main() {
Log::RemoveAllHandlers();
Log::AddLogHandler(new FileInterface("new_log_file.log"));
Log::AddLogHandler(new GraylogInterface("somehost.com", 12201));
Log::AddLogHandler(new GraylogInterface("anotherhost.com", 12202));
Log::Msg(Severity::Error, "This message will be sent to multiple Graylog servers.");
Log::Msg(Severity::Error, "This is an error.");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

## Set global severity limit
This library currently uses a single severity limit. The following code snippet illustrates how it can be used.
This library currently uses a global severity limit setting. The following code snippet illustrates how it can be used.

```c++
#include <thread>
#include <chrono>
#include <graylog_logger/Log.hpp>

int main() {
Log::Msg(Severity::Debug, "This debug message will not be shown.");
Log::SetMinimumSeverity(Severity::Debug);
Log::Msg(Severity::Debug, "This debug message will be shown.");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

The resulting output to console is a single line:
The resulting output to console is the line:

```
Debug: This debug message will be shown.
```

## Message string formating
It is possible to supply your own string formating function as shown below.
## Message string formatting
It is possible to supply your own string formatting function as shown below.

```c++
#include <thread>
#include <chrono>
#include <graylog_logger/Log.hpp>
#include <graylog_logger/ConsoleInterface.hpp>

std::string MyFormater(LogMessage &msg) {
std::string MyFormatter(LogMessage &msg) {
std::time_t cTime = std::chrono::system_clock::to_time_t(msg.timestamp);
char timeBuffer[50];
size_t bytes = std::strftime(timeBuffer, 50, "%T", std::localtime(&cTime));
Expand All @@ -132,21 +117,20 @@ std::string MyFormater(LogMessage &msg) {
int main() {
Log::RemoveAllHandlers();
auto ci = new ConsoleInterface();
ci->SetMessageStringCreatorFunction(MyFormater);
ci->SetMessageStringCreatorFunction(MyFormatter);
Log::AddLogHandler(ci);
Log::Msg(Severity::Warning, "A warning with a custom format.");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```
The output to console produced by this code is:
The definition of `struct LogMessage` can be found in the file `graylog_logger/LogUtil.hpp`. The output to console produced by this code is:
```
20:10:07 (host:Hecate, sev:4): A warning with a custom format.
```
## Message string formating
## Retrieve message handler status
Pointers to used logging interfaces can be retrieved from the logging system. This is illustrated here where the Graylog interface is singled out and its connection status is examined.
```c++
Expand All @@ -156,6 +140,7 @@ Pointers to used logging interfaces can be retrieved from the logging system. Th
#include <graylog_logger/GraylogInterface.hpp>
int main() {
Log::AddLogHandler(new GraylogInterface("somehost.com", 12201));
std::vector<LogHandler_P> interfaces = Log::GetHandlers();
auto checkFunc = [&](){for (auto h : interfaces) {
auto casted = dynamic_cast<GraylogInterface*>(h.get());
Expand All @@ -178,4 +163,73 @@ ERROR: An error message
Queued messages (true/false): 1
```

Although the library can print log messages to console very quickly, there is a slight delay when sending messages over the network. Thus in the second call to the GraylogInterface instance, the message is still queued up.
Although the library can print log messages to console very quickly, there is a slight delay when sending messages over the network. Thus in the second call to the GraylogInterface instance, the message is still queued up.

## Additional fields
The standard fields provided with every log message sent to the Graylog server are the following:

* Timestamp
* Host name
* Process id
* Process name
* Thread id
* Log message
* Severity level

It is possible to add more fields if so required and this can be done globally or on a message by message basis. Only three types of fields are currently supported:

* std::int64_t
* double
* std::string

### Additional global fields
Additional global fields are added using the `Log::AddField()` function. It can be used as follows:

```c++
int main() {
Log::AddField("some_key", "some_value");
Log::AddLogHandler(new GraylogInterface("somehost.com", 12201));
Log::Msg(Severity::Error, "This message will be sent to a Graylog servers.");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

The output to console will not change (unless you write a replacement string formatter) but every log message sent to the Graylog server will contain an extra field with the name `some_key` containing the value `some_value`. It is possible to change this value with consecutive calls to `Log::AddField()` using the same key but different value.

### Additional fields on a per message basis
Adding fields on a per message basis is done when calling the `Log::Msg()`-function. An example follows.

```c++
int main() {
Log::AddLogHandler(new GraylogInterface("somehost.com", 12201));
Log::Msg(Severity::Error, "A message.", {"another_key", 3.14});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

It is possible to add several new fields as well.

```c++
int main() {
Log::AddLogHandler(new GraylogInterface("somehost.com", 12201));
Log::Msg(Severity::Error, "A message.", {{"another_key", 3.14}, {"a_third_key", "some_other_value"}});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

Finally, an extra field added to a message will change the value (including the type) of a field set using `Log::AddField()`.

```c++
int main() {
Log::AddField("some_key", "some_value");
Log::AddLogHandler(new GraylogInterface("somehost.com", 12201));
Log::Msg(Severity::Error, "Yet another message", {"some_key", 42});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}
```

This last piece of code will send a log message to the Graylog server containing only a single extra field with the key `some_key` and the integer value `42`.
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# graylog-logger
This C++ message logging library has been developed for use at the ESS. By default, the library will write log messages to console and to TCP port 12201 on ``localhost`` in [GELF](http://docs.graylog.org/en/2.1/pages/gelf.html) format. This port will accept log messages from the library if the [graylog-machine](https://github.com/ess-dmsc/graylog-machine) [Vagrant](https://www.vagrantup.com/) machine is up and running.
This is a simple logging library which can be used to send log messages to a Graylog server. This is done by creating messages in the [GELF](http://docs.graylog.org/en/2.1/pages/gelf.html) format and sending them to a Graylog server via TCP. For testing purposes a [Vagrant](https://www.vagrantup.com/) machine running Graylog can be used. A simple Vagrantfile for creating this set-up can be [found here](https://github.com/ess-dmsc/graylog-machine). The argument for creating yet another logging library instead of writing a plugin/sink/handler for an already existing one is that a relatively light weight solution was desired. The library has functionality for writing log messages to console and file as well and by default the library will only write log messages to console.

The repository is split into three parts:

Expand All @@ -11,7 +11,7 @@ A sister project to this library is the Python logging handler [GraylogHandler](

## Requirements
The logging library uses only standard libraries with one exception: [Jsoncpp](https://github.com/open-source-parsers/jsoncpp). This library is included in the project in the form of a header file and an implementation file and will thus not require any packages to be installed.
C++11 features are used extensively and ignoring possible bugs, thread safety is only guaranteed if the compiler used has a correct C++11 (or above) implementation. Although the library should compile on most *nix systems, small differences in how sockets are handled could introduce bugs. For the same reason, the library will not compile under windows.
C++11 features are used extensively and ignoring possible bugs, thread safety is only guaranteed if the compiler used has a correct C++11 (or above) implementation. Although the library should compile on most *nix systems and, small differences in how sockets are handled could introduce bugs. The library also compiles on Windows though it can not yet transmit messages to a Graylog server on this platform.

In order to build the unit tests, the following libraries are also required:

Expand All @@ -35,7 +35,7 @@ make install
In order to only build the library, change the first lin to ```cd graylog-logger/graylog_logger``` and then follow the rest of the instructions.

### Building on Windows
The library has been tested on Windows using the Microsoft Visual C++ compiler. Assuming that CMake as well as Boost are correctly installed and that the appropriate environment variables are configured, the instructions for compiling everything are as follows:
The compilation of the library has been tested on Windows 10 using the Microsoft Visual C++ compiler (version 14.0). Assuming that CMake as well as Boost are correctly installed and that the appropriate environment variables are configured, the instructions for compiling everything are as follows:

```
cd graylog-logger
Expand All @@ -56,10 +56,10 @@ As the library only depends on standard libraries, the easiest solution is likel
### 2. Use the compiled library
If the instructions under **Build and install** are followed, a compiled binary of the library and the relevant header files will be installed into some system location. Probably ```/usr/local/```. Simply link to the library in the same way as other libraries (e.g. ```-lgraylog_logger```).

### Using the command line application
### Optional: Using the command line application
If the command line application is compiled, instructions on how to use it are shown if run without any arguments (e.g. ```./console_logger/console_logger```).

### Running the unit tests
### Optional: Running the unit tests
If compiled, the unit tests are run by running the ```unit_tests``` application in the ```unit_tests``` directory of the ```build```directory.

### Code examples
Expand All @@ -77,4 +77,15 @@ The items in the following list is in no particular order. Suggestions and/or pa
* Fix IPv4/IPv6 support
* Add UDP support
* Determine process name
* ...
* ...

##Changes

###Version 1.0

* Added support for additional (user defined) fields.
* The library will no longer attempt to connect to a Graylog server on localhost.
* Using code adopted from boost, the library should now be able to determine the current process name.
* The library now builds on Windows and passes all the unit tests. However, during integration testing it failed to correctly send log messages to a Graylog server on this platform.
* Updated the documentation.
* Minor bug fixes.
Loading

0 comments on commit d3e559c

Please sign in to comment.