Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ logging class instance identifier

Tags:

c++

c++11

In my project, some classes are instantiated more than once. Each class logs some events. The logging method is a generic one used all around the project and it uses the standard cout. The log message contains the time, name of the class, name of the method, a variable value, and a custom message.

The disadvantage is that the log is not instance specific. I do not know which instance of the class wrote the log.

Is there a nice way to solve this problem without adding additional static members as instance counters to the classes? I am using boost and C++11. Maybe boost has something that might help.

The only solution I can think of is to include the instance address (this) to the log.

like image 225
Geza Borbely Avatar asked Oct 21 '25 11:10

Geza Borbely


2 Answers

You will need to differentiate between different classes somewhere, these are a few options (all rely on some kind of ID):

  1. Add some additional static variable.
    Not an option for you, but in my opinion, the best way to go if you aim for readability.
  2. Use this, as you suggested:
    This obviously generates unique IDs, but they will tend to be unreadable and hard to distinguish with growing address lengths (as only one or two characters might differ in a lengthy address string). Also, the addresses are likely to change between every run of the application (especially when employing ASLR), so you won't be able to see which exact instance created which line of output (if that's required).
  3. Use this and hash the value:

To be honest, I don't see much of a difference to 2), but it might trigger some further ideas. Some ugly hack could look like this:

#include <iostream>
#include <functional>
#include <cstddef>

class Logger
{
public:
    static void log(void* ptr)
    {
        using hash_type = std::uintptr_t;
        std::cout << std::hash<hash_type>{}(reinterpret_cast<hash_type>(ptr))
            << " logged something..." << std::endl;
    }
};

You can also consider specializing std::hash for your classes and use that in the logging output. This would remove the problem of changing addresses between different runs, if implemented properly.

  1. Generate an ID during construction (e.g. by passing some identifier to the constructor):
    This is not really an option since you have no evidence or control that a unique ID is generated for each class - unless you use some kind of (abstract) factory with access to a private constructor or some kind of global registry (see below).
  2. Use some helper utility where your logging classes are registered and unique IDs are generated (something like a registration class).
    For simple logging purposes, IMHO this is bloat and does not add any value compared to 1).

Conclusion: I would go for option 1) if readability for humans is of concern and for 2) if you simply want some number to distinguish between log messages (e.g. for piping and filtering).

like image 129
andreee Avatar answered Oct 24 '25 01:10

andreee


You can quite easily generate IDs via CRTP adaptor like that (if you can modify your classes a bit)

template<typename T>
struct enable_id
{
    int id = global_id++;
private:
    static int global_id;
};

template<typename T>
int enable_id<T>::global_id = 0;

class foo : public enable_id<foo>
{
};

template<typename T>
void log(const T& t)
{
    // if is_base_of
    std::cout << t.id << std::endl;
}
like image 43
Zereges Avatar answered Oct 24 '25 00:10

Zereges



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!