445 lines
14 KiB
C++
445 lines
14 KiB
C++
/***************************************************************************
|
|
* Copyright (C) gempa GmbH *
|
|
* All rights reserved. *
|
|
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
|
* *
|
|
* GNU Affero General Public License Usage *
|
|
* This file may be used under the terms of the GNU Affero *
|
|
* Public License version 3.0 as published by the Free Software Foundation *
|
|
* and appearing in the file LICENSE included in the packaging of this *
|
|
* file. Please review the following information to ensure the GNU Affero *
|
|
* Public License version 3.0 requirements will be met: *
|
|
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
|
* *
|
|
* Other Usage *
|
|
* Alternatively, this file may be used in accordance with the terms and *
|
|
* conditions contained in a signed written agreement between you and *
|
|
* gempa GmbH. *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef SC_LOGGING_LOGGING_H
|
|
#define SC_LOGGING_LOGGING_H
|
|
|
|
#ifndef SEISCOMP_COMPONENT
|
|
# ifndef WIN32
|
|
# warning SEISCOMP_COMPONENT not defined -> setting to "Seiscomp"
|
|
# endif
|
|
# define SEISCOMP_COMPONENT "Seiscomp"
|
|
#endif
|
|
|
|
/* Define that SEISCOMP_* are also available as variadic versions, e.g.
|
|
SEISCOMP_ERROR and SEISCOMP_VERROR whereas the latter takes an argument
|
|
list (fmt::printf_args), e.g. SEISCOMP_VERROR("%s:%d", args).
|
|
*/
|
|
#define SEISCOMP_LOG_VA
|
|
#define SEISCOMP_LOG_API_VERSION 2
|
|
|
|
#include <seiscomp/logging/publisher.h>
|
|
#include <seiscomp/logging/publishloc.h>
|
|
#include <seiscomp/logging/publisher.h>
|
|
#include <seiscomp/logging/common.h>
|
|
#include <seiscomp/logging/defs.h>
|
|
|
|
|
|
namespace Seiscomp {
|
|
namespace Logging {
|
|
|
|
|
|
class Channel;
|
|
class Output;
|
|
|
|
|
|
enum LogLevel {
|
|
LL_UNDEFINED = 0,
|
|
LL_CRITICAL,
|
|
LL_ERROR,
|
|
LL_WARNING,
|
|
LL_NOTICE,
|
|
LL_INFO,
|
|
LL_DEBUG,
|
|
LL_QUANTITY
|
|
};
|
|
|
|
|
|
/**
|
|
\brief The following macros do the actual logging according
|
|
\brief defined log levels
|
|
The first parameter is the message including placeholders (printf style),
|
|
the following parameters hold the values.
|
|
\code
|
|
SEISCOMP_[LEVEL]("Precondition not satisfied: i > %d", myVarHolding_i);
|
|
\endcode
|
|
*/
|
|
|
|
#define STR(X) #X
|
|
|
|
|
|
#ifdef __FUNCTION__
|
|
# define SEISCOMP_LOGGING_CURRENT_FUNCTION __FUNCTION__
|
|
#else
|
|
# define SEISCOMP_LOGGING_CURRENT_FUNCTION "[unknown]"
|
|
#endif
|
|
|
|
#define SEISCOMP_LOGGING_CALL(ID, COMPONENT, CHANNEL, FUNC, ...) \
|
|
static bool ID ## _enabled = true; \
|
|
if ( unlikely(ID ## _enabled) ) { \
|
|
static Seiscomp::Logging::PublishLoc ID(& ID ## _enabled, \
|
|
STR(COMPONENT), __FILE__, \
|
|
SEISCOMP_LOGGING_CURRENT_FUNCTION, \
|
|
__LINE__, CHANNEL); \
|
|
FUNC(&ID, CHANNEL, ##__VA_ARGS__); \
|
|
}
|
|
|
|
|
|
#define _scplain(ID, CHANNEL, MSG) \
|
|
do { SEISCOMP_LOGGING_CALL(ID, SEISCOMP_COMPONENT, CHANNEL, Seiscomp::Logging::Publish, MSG) } while(0)
|
|
|
|
#define _scfmt(ID, CHANNEL, ... ) \
|
|
do { SEISCOMP_LOGGING_CALL(ID, SEISCOMP_COMPONENT, CHANNEL, Seiscomp::Logging::PublishF, ##__VA_ARGS__) } while(0)
|
|
|
|
#define _scprintf(ID, CHANNEL, ... ) \
|
|
do { SEISCOMP_LOGGING_CALL(ID, SEISCOMP_COMPONENT, CHANNEL, Seiscomp::Logging::PublishP, ##__VA_ARGS__) } while(0)
|
|
|
|
#define _scv(ID, CHANNEL, format, args) \
|
|
do { SEISCOMP_LOGGING_CALL(ID, SEISCOMP_COMPONENT, CHANNEL, Seiscomp::Logging::VPublish, format, args) } while(0)
|
|
|
|
|
|
/*! @addtogroup LoggingMacros
|
|
These macros are the primary interface for logging messages:
|
|
- SEISCOMP_DEBUG(format, ...)
|
|
- SEISCOMP_INFO(format, ...)
|
|
- SEISCOMP_WARNING(format, ...)
|
|
- SEISCOMP_ERROR(format, ...)
|
|
- SEISCOMP_NOTICE(format, ...)
|
|
- SEISCOMP_LOG(channel, format, ...)
|
|
@{
|
|
*/
|
|
|
|
/*! @def SEISCOMP_DEBUG(format, ...)
|
|
@brief Log a message to the "debug" channel. Takes printf style arguments.
|
|
|
|
Format is ala printf, eg:
|
|
@code
|
|
SEISCOMP_DEBUG("I'm sorry %s, I can't do %s", name, request);
|
|
@endcode
|
|
|
|
When using a recent GNU compiler, it should automatically detect format
|
|
string / argument mismatch just like it would with printf.
|
|
|
|
Note that unless there are subscribers to this message, it will do nothing.
|
|
*/
|
|
#define SEISCOMP_DEBUG(...) \
|
|
_scprintf(_SCLOGID, Seiscomp::Logging::_SCDebugChannel, ##__VA_ARGS__)
|
|
|
|
#define SC_FMT_DEBUG(...) \
|
|
_scfmt(_SCLOGID, Seiscomp::Logging::_SCDebugChannel, ##__VA_ARGS__)
|
|
|
|
#define SEISCOMP_VDEBUG(format, args) \
|
|
_scv(_SCLOGID, Seiscomp::Logging::_SCDebugChannel, format, args)
|
|
|
|
/*! @def SEISCOMP_INFO(format, ...)
|
|
@brief Log a message to the "info" channel. Takes printf style arguments.
|
|
|
|
Format is ala printf, eg:
|
|
@code
|
|
SEISCOMP_INFO("I'm sorry %s, I can't do %s", name, request);
|
|
@endcode
|
|
|
|
When using a recent GNU compiler, it should automatically detect format
|
|
string / argument mismatch just like it would with printf.
|
|
|
|
Note that unless there are subscribers to this message, it will do nothing.
|
|
*/
|
|
#define SEISCOMP_INFO(...) \
|
|
_scprintf(_SCLOGID, Seiscomp::Logging::_SCInfoChannel, ##__VA_ARGS__)
|
|
|
|
#define SC_FMT_INFO(...) \
|
|
_scfmt(_SCLOGID, Seiscomp::Logging::_SCInfoChannel, ##__VA_ARGS__)
|
|
|
|
#define SEISCOMP_VINFO(format, args) \
|
|
_scv(_SCLOGID, Seiscomp::Logging::_SCInfoChannel, format, args)
|
|
|
|
/*! @def SEISCOMP_WARNING(format, ...)
|
|
@brief Log a message to the "warning" channel. Takes printf style
|
|
arguments.
|
|
|
|
Output a warning message - meant to indicate that something doesn't seem
|
|
right.
|
|
|
|
Format is ala printf, eg:
|
|
@code
|
|
SEISCOMP_WARNING("passed %i, expected %i, continuing", foo, bar);
|
|
@endcode
|
|
|
|
When using a recent GNU compiler, it should automatically detect format
|
|
string / argument mismatch just like it would with printf.
|
|
|
|
Note that unless there are subscribers to this message, it will do nothing.
|
|
*/
|
|
#define SEISCOMP_WARNING(...) \
|
|
_scprintf(_SCLOGID, Seiscomp::Logging::_SCWarningChannel, ##__VA_ARGS__)
|
|
|
|
#define SC_FMT_WARNING(...) \
|
|
_scfmt(_SCLOGID, Seiscomp::Logging::_SCWarningChannel, ##__VA_ARGS__)
|
|
|
|
#define SEISCOMP_VWARNING(format, args) \
|
|
_scv(_SCLOGID, Seiscomp::Logging::_SCWarningChannel, format, args)
|
|
|
|
/*! @def SEISCOMP_ERROR(...)
|
|
@brief Log a message to the "error" channel. Takes printf style arguments.
|
|
|
|
An error indicates that something has definately gone wrong.
|
|
|
|
Format is ala printf, eg:
|
|
@code
|
|
SEISCOMP_ERROR("bad input %s, aborting request", input);
|
|
@endcode
|
|
|
|
When using a recent GNU compiler, it should automatically detect format
|
|
string / argument mismatch just like it would with printf.
|
|
|
|
Note that unless there are subscribers to this message, it will do nothing.
|
|
*/
|
|
#define SEISCOMP_ERROR(...) \
|
|
_scprintf(_SCLOGID, Seiscomp::Logging::_SCErrorChannel, ##__VA_ARGS__)
|
|
|
|
#define SC_FMT_ERROR(...) \
|
|
_scfmt(_SCLOGID, Seiscomp::Logging::_SCErrorChannel, ##__VA_ARGS__)
|
|
|
|
#define SEISCOMP_VERROR(format, args) \
|
|
_scv(_SCLOGID, Seiscomp::Logging::_SCErrorChannel, format, args)
|
|
|
|
/*! @def SEISCOMP_NOTICE(...)
|
|
@brief Log a message to the "notice" channel. Takes printf style arguments.
|
|
|
|
A notice indicates that something important happened.
|
|
|
|
Format is ala printf, eg:
|
|
@code
|
|
SEISCOMP_NOTICE("bad input %s, aborting request", input);
|
|
@endcode
|
|
|
|
When using a recent GNU compiler, it should automatically detect format
|
|
string / argument mismatch just like it would with printf.
|
|
|
|
Note that unless there are subscribers to this message, it will do nothing.
|
|
*/
|
|
#define SEISCOMP_NOTICE(...) \
|
|
_scprintf(_SCLOGID, Seiscomp::Logging::_SCNoticeChannel, ##__VA_ARGS__)
|
|
|
|
#define SC_FMT_NOTICE(...) \
|
|
_scfmt(_SCLOGID, Seiscomp::Logging::_SCNoticeChannel, ##__VA_ARGS__)
|
|
|
|
#define SEISCOMP_VNOTICE(format, args) \
|
|
_scv(_SCLOGID, Seiscomp::Logging::_SCNoticeChannel, format, args)
|
|
|
|
/*! @def SEISCOMP_LOG(channel,format,...)
|
|
@brief Log a message to a user defined channel. Takes a channel and printf
|
|
style arguments.
|
|
|
|
An error indicates that something has definately gone wrong.
|
|
|
|
Format is ala printf, eg:
|
|
@code
|
|
static Channel * MyChannel = SEISCOMP_CHANNEL("debug/mine");
|
|
SEISCOMP_LOG(MyChannel, "happy happy, joy joy");
|
|
@endcode
|
|
|
|
When using a recent GNU compiler, it should automatically detect format
|
|
string / argument mismatch just like it would with printf.
|
|
|
|
Note that unless there are subscribers to this message, it will do nothing.
|
|
*/
|
|
#define SEISCOMP_LOG(channel, ...) \
|
|
_scprintf(_SCLOGID, channel, ##__VA_ARGS__)
|
|
|
|
#define SC_FMT_LOG(channel, ...) \
|
|
_scfmt(_SCLOGID, channel, ##__VA_ARGS__)
|
|
|
|
#define SEISCOMP_VLOG(channel, format, args) \
|
|
_scv(_SCLOGID, channel, format, args)
|
|
|
|
/*! @def DEF_CHANNEL( const char *path, LogLevel level )
|
|
@brief Returns pointer to Channel struct for the given path
|
|
@param path The hierarchical path to the channel. Elements in the path
|
|
are separated by '/'.
|
|
|
|
SEISCOMP_DEF_LOGCHANNEL gets an existing (or defines a new) log type. For example
|
|
"debug", "warning", "error" are predefined types. You might define
|
|
completely new types, like "timing", or perhaps sub-types like
|
|
"debug/timing/foo", depending on your needs.
|
|
|
|
Reporting paths do not need to be unique within a project (or even a
|
|
file).
|
|
|
|
Channels form a hierarchy. If one subscribes to "debug", then you also
|
|
get messages posted to more specific types such as "debug/foo". But if
|
|
you subscribe to a more specific type, such as "debug/foo", then you will
|
|
not receive more general messages such as to "debug".
|
|
|
|
Example:
|
|
@code
|
|
#include <seiscomp/logging/log.h>
|
|
#include <seiscomp/logging/channel.h>
|
|
|
|
static Channel *MyChannel = SEISCOMP_DEF_LOGCHANNEL("me/mine/allmine",Log_Info);
|
|
|
|
func()
|
|
{
|
|
SEISCOMP_LOG( MyChannel, "this is being sent to my own channel" );
|
|
SEISCOMP_LOG( MyChannel, "%s %s", "hello", "world" );
|
|
}
|
|
|
|
main()
|
|
{
|
|
// log all messages to the "me" channel to stderr
|
|
StdioNode stdLog( STDERR_FILENO );
|
|
stdLog.subscribeTo( SEISCOMP_CHANNEL ("me") );
|
|
|
|
func();
|
|
}
|
|
@endcode
|
|
|
|
@see test.cpp
|
|
*/
|
|
|
|
#define SEISCOMP_DEF_LOGCHANNEL(path,level) SEISCOMP_CHANNEL_IMPL(SEISCOMP_COMPONENT, path, level)
|
|
#define SEISCOMP_CHANNEL(path) SEISCOMP_CHANNEL_IMPL(SEISCOMP_COMPONENT, path, Seiscomp::Logging::LL_UNDEFINED)
|
|
#define SEISCOMP_CHANNEL_IMPL(COMPONENT,path,level) \
|
|
Seiscomp::Logging::getComponentChannel(LOG_STR(COMPONENT),path,level)
|
|
|
|
|
|
#define SEISCOMP_DEBUG_S(str) \
|
|
_scplain(_SCLOGID, Seiscomp::Logging::_SCDebugChannel, str)
|
|
|
|
#define SEISCOMP_INFO_S(str) \
|
|
_scplain(_SCLOGID, Seiscomp::Logging::_SCInfoChannel, str)
|
|
|
|
#define SEISCOMP_WARNING_S(str) \
|
|
_scplain(_SCLOGID, Seiscomp::Logging::_SCWarningChannel, str)
|
|
|
|
#define SEISCOMP_ERROR_S(str) \
|
|
_scplain(_SCLOGID, Seiscomp::Logging::_SCErrorChannel, str)
|
|
|
|
#define SEISCOMP_NOTICE_S(str) \
|
|
_scplain(_SCLOGID, Seiscomp::Logging::_SCNoticeChannel, str)
|
|
|
|
#define SEISCOMP_LOG_S(channel, str) \
|
|
_scplain(_SCLOGID, channel, str)
|
|
|
|
/**
|
|
Loglevel "LOG" is a special level, which needs a channel, to
|
|
log the message to.
|
|
\code
|
|
static Channel* MyChannel = SEISCOMP_DEF_LOGCHANNEL("myroot/mysub", Log_Error);
|
|
SEISCOMP_LOG(myChannel, "Postcondition not satisfied: count2 [%d] <= count1 [%d]", count2, count1);
|
|
\endcode
|
|
*/
|
|
|
|
SC_SYSTEM_CORE_API void debug(const char*);
|
|
SC_SYSTEM_CORE_API void debug(const std::string &);
|
|
SC_SYSTEM_CORE_API void info(const char*);
|
|
SC_SYSTEM_CORE_API void info(const std::string &);
|
|
SC_SYSTEM_CORE_API void warning(const char*);
|
|
SC_SYSTEM_CORE_API void warning(const std::string &);
|
|
SC_SYSTEM_CORE_API void error(const char*);
|
|
SC_SYSTEM_CORE_API void error(const std::string &);
|
|
SC_SYSTEM_CORE_API void notice(const char*);
|
|
SC_SYSTEM_CORE_API void notice(const std::string &);
|
|
SC_SYSTEM_CORE_API void log(Channel*, const char*);
|
|
SC_SYSTEM_CORE_API void log(Channel*, const std::string &);
|
|
|
|
|
|
/** NOTE: All retrieved Channel pointer must not be deleted!!! */
|
|
|
|
/** Retrieve all messages from all components */
|
|
SC_SYSTEM_CORE_API Channel *getAll();
|
|
|
|
/*! @relates Channel
|
|
@brief Return the named channel across all components.
|
|
|
|
Channels are hierarchical. See Channel for more detail.
|
|
The global channel contains messages for all component channels.
|
|
|
|
For example, subscribing to the global "debug" means the subscriber would
|
|
also get messages from <Component , "debug">, and <Component-B, "debug">, and
|
|
<Component-C, "debug/foo">, etc.
|
|
|
|
@author Valient Gough
|
|
*/
|
|
SC_SYSTEM_CORE_API Channel *getGlobalChannel(const char *channel, LogLevel level = LL_UNDEFINED);
|
|
|
|
/*! @relates Channel
|
|
@brief Return the named channel for a particular component.
|
|
|
|
@author Valient Gough
|
|
*/
|
|
SC_SYSTEM_CORE_API Channel *getComponentChannel(const char *component, const char *channel, LogLevel level = LL_UNDEFINED);
|
|
|
|
/** Retrieve defined messages from a component */
|
|
SC_SYSTEM_CORE_API Channel *getComponentAll(const char *component);
|
|
SC_SYSTEM_CORE_API Channel *getComponentDebugs(const char *component);
|
|
SC_SYSTEM_CORE_API Channel *getComponentInfos(const char *component);
|
|
SC_SYSTEM_CORE_API Channel *getComponentWarnings(const char *component);
|
|
SC_SYSTEM_CORE_API Channel *getComponentErrors(const char *component);
|
|
SC_SYSTEM_CORE_API Channel *getComponentNotices(const char *component);
|
|
|
|
|
|
/**
|
|
\brief Example on how to use logging
|
|
|
|
File: [name].cpp
|
|
\code
|
|
// NOTE: The definition of component has to be done before the include
|
|
// of log.h !
|
|
#define SEISCOMP_COMPONENT MyComponent
|
|
#include <seiscomp/logging/log.h>
|
|
|
|
// include further header
|
|
...
|
|
|
|
void foo(int i) {
|
|
if ( i < 0 ) {
|
|
SEISCOMP_WARNING("precondition: i >= 0 not satisfied, i = %d", i);
|
|
return;
|
|
}
|
|
|
|
SEISCOMP_INFO("postcondition satisfied");
|
|
}
|
|
\endcode
|
|
|
|
To subscribe logging channels and to output logging messages,
|
|
create a node and subscribe the channels of interest.
|
|
\code
|
|
int main(int argc, char** argv) {
|
|
SeisComp::Logging::Init(argc, argv);
|
|
...
|
|
// create one default node and log to stderr
|
|
Seiscomp::Logging::FdOutput stdLog(STDERR_FILENO);
|
|
// lets receive all warnings from the component MyComponent (see above).
|
|
stdLog.subscribe(Seiscomp::Logging::GetComponentWarnings("MyComponent"));
|
|
...
|
|
// dont catch any messages
|
|
stdLog.clear();
|
|
// lets receive all messages from the component MyComponent
|
|
stdLog.subscribe(Seiscomp::Logging::GetComponentAll("MyComponent"));
|
|
...
|
|
// subscribe to all messages globally
|
|
stdLog.subscribe(Seiscomp::Logging::GetAll());
|
|
|
|
}
|
|
\endcode
|
|
*/
|
|
|
|
|
|
SC_SYSTEM_CORE_API Output* consoleOutput();
|
|
SC_SYSTEM_CORE_API void enableConsoleLogging(Channel*);
|
|
SC_SYSTEM_CORE_API void disableConsoleLogging();
|
|
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|