• We’re currently investigating an issue related to the forum theme and styling that is impacting page layout and visual formatting. The problem has been identified, and we are actively working on a resolution. There is no impact to user data or functionality, this is strictly a front-end display issue. We’ll post an update once the fix has been deployed. Thanks for your patience while we get this sorted.

Help with globally-scoped logging object?

scootermaster

Platinum Member
So I'm using a tweaked version of the simple logging library provided here:

http://www.drdobbs.com/cpp/201804215;jsessionid=IGOKPTDNZB0JBQE1GHPCKH4ATMY32JVN?pgno=3

On the example code, they instantiate a logging object like this, using a macro given below (in main):

Code:
FILELog::ReportingLevel() = FILELog::FromString(argv[1] ? argv[1] : "DEBUG1");

Other relevant parts of the code are the class definition:

Code:
template <typename T>
class Log
{
public:
    Log();
    virtual ~Log();
    std::ostringstream& Get(TLogLevel level = logINFO);  // Sets up actual logging string, defaults level to logINFO
public:
    static TLogLevel& ReportingLevel();
    static std::string ToString(TLogLevel level);
    static TLogLevel FromString(const std::string& level);
protected:
    std::ostringstream os;
private:
    Log(const Log&);
    Log& operator =(const Log&);
};

and the macro that's above from main

Code:
#define FILE_LOG(level) \
    if (level > FILELOG_MAX_LEVEL) ;\
    else if (level > FILELog::ReportingLevel() || !Output2FILE::Stream()) ; \
    else FILELog().Get(level)

And finally, this (which I'm not even sure what it does, other than defined a weirdly unnamed class)

Code:
class FILELOG_DECLSPEC FILELog : public Log<Output2FILE> {};

The "get" function just builds a stream object (that is then printed somewhere) and the Output2File class has functions that send it to the screen (or, after much tinkering, to an output file. Another question I had was how to paramterize that, but I ended up just making 2 separate classes and creating two objects).

So my question is this: So far this works wonderfully in main. But how can I get this to work globally across a number of different files? I guess it's not super essential (I could just instantiate a new logging thingee for each file/class I'm using, seeing as the file descriptor to the screen (stderr) will be the same, and if I open the same file each time, it [should] just interleave the logging statements, but that seems ugly. So is there a way to access a single logging object from, say, test.h or test.cc (within class objects in those files)?

Is there a way of doing this? Thanks!
 
I didn't go through your code, but conceptually what you're looking for is the "extern" keyword.
 
I didn't go through your code, but conceptually what you're looking for is the "extern" keyword.

Yeah, that part I know. I'm dumb, but I'm not that dumb.

What I don't get is exactly where the damn object is declared, and what the eff I call it when I call extern.

All those fancy cycle-saving tricks, liking using the inlines and the macro expansions and the templated functions confuse me (see me being dumb, above).

Any idea what I'm supposed to extern? And can I even declare the logging object in global main [file] space using those macros and that weird if/then shorthand? I'm pretty sure that stuff won't fly in global space.
 
On the example code, they instantiate a logging object like this, using a macro given below (in main):
Code:
FILELog::ReportingLevel() = FILELog::FromString(argv[1] ? argv[1] : "DEBUG1");

This isn't instantiating the log -- its setting a global member (aka static member) of the FILELog class. You're going to have to find the real instantiation somewhere else, before you will know...

Any idea what I'm supposed to extern?

Once you find the real instantiation, yes. It will probably look something like this:
Code:
FILELog log;
Or possibly:
Code:
FILELOG *p_log;

If the former, extern like this:
Code:
extern FILELog log;
Else:
Code:
extern FILELog* p_log;

That will give the object global scope among any file that extern's as above. Bear in mind that the latter will require you to actually instantiate the object somewhere, e.g., in main with:
Code:
p_log = new FILELog();
 
FILE_LOG creates a new object each time, so there is global object and nothing to extern. Put the OutputFILE2 and FILELog classes in a header and FILE_LOG be used anywhere in the application.
 
FILE_LOG creates a new object each time, so there is global object and nothing to extern. Put the OutputFILE2 and FILELog classes in a header and FILE_LOG be used anywhere in the application.

Yeah, thanks! I realized I kinda said that above, but if every call creates (and destroys, since it's the destructor that actually does the output and calls fflush) then it as long as the class is scoped correctly, I can call it from anywhere.

That's finally what I was looking for. 😀 (I think).
 
Back
Top