[seiscomp, scanloc] Install, add .gitignore

This commit is contained in:
2025-10-09 15:07:02 +02:00
commit 20f5301bb1
2848 changed files with 1315858 additions and 0 deletions

View File

@ -0,0 +1,114 @@
/***************************************************************************
* 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_CHANNEL_H
#define SC_LOGGING_CHANNEL_H
#include <string>
#include <map>
#include <seiscomp/logging/log.h>
#include <seiscomp/logging/node.h>
namespace Seiscomp {
namespace Logging {
/*! @class Seiscomp::Logging::Channel <seiscomp/logging/channel.h>
@brief Implements a hierarchical logging channel
You should not need to use Channel directly under normal
circumstances. See COMPONENT_CHANNEL() macro, GetComponentChannel() and
getGlobalChannel()
Channel implements channel logging support. A channel is a named
logging location which is global to the program. Channels are
hierarchically related.
For example, if somewhere in your program a message is logged to
"debug/foo/bar", then it will be delived to any subscribers to
"debug/foo/bar", or subscribers to "debug/foo", or subscribers to
"debug". Subscribing to a channel means you will receive anything
published on that channel or sub-channels.
As a special case, subscribing to the channel "" means you will receive
all messages - as every message has a channel and the empty string "" is
considered to mean the root of the channel tree.
In addition, componentized channels are all considered sub channels of
the global channel hierarchy. All rDebug(), rWarning(), and rError()
macros publish to the componentized channels (component defined by
SEISCOMP_COMPONENT).
@code
// get the "debug" channel for our component. This is the same as
// what rDebug() publishes to.
Channel *node = COMPONENT_CHANNEL("debug", Log_Debug);
// equivalent to
Channel *node = GetComponentChannel(SEISCOMP_COMPONENT, "debug");
// Or, get the global "debug" channel, which will have messages from
// *all* component's "debug" channels.
Channel *node = getGlobalChannel( "debug", Log_Debug );
@endcode
@author Valient Gough
@see COMPONENT_CHANNEL()
@see getComponentChannel()
@see getGlobalChannel()
*/
class SC_SYSTEM_CORE_API Channel : public Node {
public:
using ComponentMap = std::map<std::string, Channel*>;
Channel(const std::string &name, LogLevel level);
virtual ~Channel();
virtual void publish(const Data &data);
const std::string &name() const;
LogLevel logLevel() const;
void setLogLevel(LogLevel level);
protected:
Channel *getComponent(Channel *componentParent,
const char *component);
private:
//! the full channel name
std::string _name;
LogLevel _level;
ComponentMap subChannels;
ComponentMap components;
Channel(const Channel &);
Channel &operator=(const Channel&);
friend Channel *Seiscomp::Logging::getComponentChannel(
const char *component,
const char *path,
LogLevel level);
};
}
}
#endif

View File

@ -0,0 +1,82 @@
/***************************************************************************
* 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_COMMON_H
#define SC_LOGGING_COMMON_H
#include <seiscomp/core.h>
#define LOG_CONCAT2(A,B) A##B
#define LOG_CONCAT(A,B) LOG_CONCAT2(A,B)
#define LOG_STR(X) #X
/*
We use __printf__ attribute to allow gcc to inspect printf style arguments
and give warnings if the rDebug(), rWarning(), etc macros are misused.
We use __builtin_expect on GCC 2.96 and above to allow optimization of
publication activation check. We tell the compiler that the branch is
unlikely to occur, allowing GCC to push unecessary code out of the main
path.
*/
#ifdef __GNUC__
# define likely(x) __builtin_expect((x),1)
# define unlikely(x) __builtin_expect((x),0)
#else
// Not using the gcc compiler, make the macros do nothing.. They are
// documented as the last instance of the macros..
/*!
*/
# define likely(x) (x)
/*! @def unlikely(x)
Starting with GCC 2.96, we can tell the compiler that an if condition is
likely or unlikely to occur, which allows the compiler to optimize for the
normal case.
@internal
*/
# define unlikely(x) (x)
#endif
/*! @def SEISCOMP_COMPONENT
@brief Specifies build-time component, eg -DSEISCOMP_COMPONENT="component-name"
Define SEISCOMP_COMPONENT as the name of the component being built.
For example, as a compile flag, -DSEISCOMP_COMPONENT="component-name"
If SEISCOMP_COMPONENT is not specified, then it will be defined as "[unknown]"
*/
#ifndef SEISCOMP_COMPONENT
# warning SEISCOMP_COMPONENT not defined - setting to UNKNOWN
#define SEISCOMP_COMPONENT "[unknown]"
#endif // SEISCOMP_COMPONENT not defined
// Use somewhat unique names (doesn't matter if they aren't as they are used in
// a private context, so the compiler will make them unique if it must)
#define _SCLOGID LOG_CONCAT(_rL_, __LINE__)
#endif

View File

@ -0,0 +1,42 @@
/***************************************************************************
* 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_DEFS_H
#define SC_LOGGING_DEFS_H
#include <seiscomp/core.h>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API Channel;
SC_SYSTEM_CORE_API extern Channel *_SCDebugChannel;
SC_SYSTEM_CORE_API extern Channel *_SCInfoChannel;
SC_SYSTEM_CORE_API extern Channel *_SCWarningChannel;
SC_SYSTEM_CORE_API extern Channel *_SCErrorChannel;
SC_SYSTEM_CORE_API extern Channel *_SCNoticeChannel;
}
}
#endif

View File

@ -0,0 +1,52 @@
/***************************************************************************
* 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_FD_H
#define SC_LOGGING_FD_H
#include <seiscomp/logging/output.h>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API FdOutput : public Output {
public:
FdOutput(int fdOut = 2);
~FdOutput();
protected:
/** Callback method for receiving log messages */
void log(const char* channelName,
LogLevel level,
const char* msg,
time_t time);
private:
bool _colorize;
int _fdOut;
};
}
}
#endif

View File

@ -0,0 +1,57 @@
/***************************************************************************
* 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_FILE_H
#define SC_LOGGING_FILE_H
#include <seiscomp/logging/output.h>
#include <fstream>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API FileOutput : public Output {
public:
FileOutput();
FileOutput(const char* filename);
~FileOutput();
virtual bool open(const char* filename);
bool isOpen();
protected:
/** Callback method for receiving log messages */
void log(const char* channelName,
LogLevel level,
const char* msg,
time_t time);
protected:
std::string _filename;
mutable std::ofstream _stream;
};
}
}
#endif

View File

@ -0,0 +1,81 @@
/***************************************************************************
* 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_FILEROTATOR_H
#define SC_LOGGING_FILEROTATOR_H
#include <seiscomp/logging/file.h>
#include <mutex>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API FileRotatorOutput : public FileOutput {
public:
FileRotatorOutput(int timeSpan = 60*60*24, int historySize = 7,
int maxFileSize = 100*1024*1024);
/**
* Creates a new FileRotatorOutput instance
* @param filename The filename to log to
* @param timeSpan The timespan in seconds for the log time before rotating
* @param count The number of historic files to store
*/
FileRotatorOutput(const char* filename, int timeSpan = 60*60*24,
int historySize = 7, int maxFileSize = 100*1024*1024);
bool open(const char* filename);
protected:
/** Callback method for receiving log messages */
void log(const char* channelName,
LogLevel level,
const char* msg,
time_t time);
private:
void rotateLogs();
void removeLog(int index);
void renameLog(int oldIndex, int newIndex);
protected:
//! time span to keep one log
int _timeSpan;
//! number of log files to keep
int _historySize;
//! maximum file size of a log file
int _maxFileSize;
//! last log file written to
int _lastInterval;
std::mutex outputMutex;
};
}
}
#endif

View File

@ -0,0 +1,444 @@
/***************************************************************************
* 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

View File

@ -0,0 +1,196 @@
/***************************************************************************
* 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_NODE_H
#define SC_LOGGING_NODE_H
#include <list>
#include <set>
#include <time.h>
#include <string>
#include <mutex>
#include <seiscomp/core.h>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API Node;
/*! @struct Data <seiscomp/logging/node.h>
* @brief Data published through Node
Data is the data which is published from SEISCOMP_DEBUG(), SEISCOMP_WARNING(),
SEISCOMP_ERROR() and SEISCOMP_LOG() macros. It contains a link to the
publisher, the (approximate) time of the publication, and the formatted message.
Note that none of the data in the publication is considered to be static.
Once control has returned to the publisher, the data may be destroyed. If
it is necessary to hang on to any of the data, a deep copy must be made.
*/
struct SC_SYSTEM_CORE_API Data {
struct PublishLoc *publisher;
//! time of publication
time_t time;
//! formatted msg - gets destroyed when publish() call returns.
const char *msg;
// track which nodes have seen this message, to avoid getting
// duplicates. It would be nice if we could enforce this via the node
// structure instead, but that is much harder.
std::set<Node*> seen;
};
/*! @class Seiscomp::Logging::Node <seiscomp/logging/node.h>
@brief Core of publication system, forms activation network.
Node formes the core of the publication system. It has two primary
purposes :
- link publications with subscribers
- transfer meta-data in the form or node activations
Both publishers (eg Publisher) and subscribers (eg StdioNode) are
derived from Node, although Node can be used entirely unmodified.
An Node contains a list of publishers which it is linked with. It
also contains a list of subscribers which it is linked with.
Publications always flow from publishers to subscribers, and activation
information flows the opposite direction from subscribers to publishers.
An Node by default acts as both a subscriber and publisher -- when
it has been subscribed to another node and receives a publication it
simply repeats the information to all of its subscribers.
More specifically, it only publishes to subscribers who have also voiced
an interest in receiving the publication. If a node has no subscribers
which are also interested (or no subscribers at all), then it can be said
to be dormant and it tells the publishers that it is subscribed to that
it is no longer interested. This propogates all the way up to
Publishers which will disable the logging statement completely if
there are no interested parties.
@author Valient Gough
*/
class SC_SYSTEM_CORE_API Node {
public:
//! @brief Instantiate an empty Node. No subscribers or publishers..
Node();
//! @brief Disconnects from any remaining subscribers and publishers
virtual ~Node();
//! @brief Force disconnection from any subscribers or publishers
virtual void clear();
/*! @brief Publish data.
This iterates over the list of subscribers which have stated interest and
sends them the data.
*/
virtual void publish(const Data &data);
/*! @brief Have this node subscribe to a new publisher.
We become a subscriber of the publisher. The publisher's addSubscriber()
function is called to complete the link.
If our node is active then we also tell the publisher that we want
publications.
*/
virtual void addPublisher(Node *);
/*! @brief Drop our subscription to a publisher
A callback parameter is provided to help avoid loops in the code which may
affect the thread locking code.
@param callback If True, then we call publisher->dropSubscriber() to make
sure the publisher also drops us as a subscriber.
*/
virtual void dropPublisher(Node *, bool callbacks=true );
/*! @brief Returns @e true if this node is active
@return @e true if we have one or more interested subscribers, otherwise false
*/
bool enabled() const;
/*! @brief Add a subscriber.
Normally a subscriber calls this for itself when it's addPublisher() method is
called.
*/
virtual void addSubscriber(Node *);
/*! @brief Remove a subscriber.
Normally a subscriber calls this for itself when it's dropPublisher() method
is called.
Note that the subscriber list is kept separate from the interest list. If
the subscriber is active, then you must undo that by calling
isInterested(subscriber, false) in addition to dropSubscriber
*/
virtual void dropSubscriber(Node *);
/*! @brief Change the state of one of our subscribers.
This allows a subscriber to say that it wants to be notified of publications
or not. The @a node should already be registered as a subscriber.
If we previously had no interested parties and now we do, then we need to
notify the publishers in our publishers list that we are now interested.
If we previously had interested parties and we remove the last one, then we
can notify the publishers that we are no longer interested..
*/
virtual void isInterested(Node *node, bool isInterested);
protected:
/*! @brief For derived classes to get notified of activation status change.
This is called by isInterested() when our state changes. If @e true is
passed, then this node has become active. If @e false is passed, then this
node has just become dormant.
*/
virtual void setEnabled(bool newState);
//! list of nodes we are subscribed to
std::list<Node *> publishers;
//! list of nodes we publish to
std::list<Node *> subscribers;
//! list of subscribers that are interested in receiving publications..
std::list<Node *> interestList;
std::mutex mutex;
};
}
}
#endif

View File

@ -0,0 +1,92 @@
/***************************************************************************
* 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_OUTPUT_H
#define SC_LOGGING_OUTPUT_H
#include <seiscomp/logging/node.h>
#include <seiscomp/logging/log.h>
namespace Seiscomp {
namespace Logging {
/**
* \brief Logging output class
*
* To implement a special kind of logging output,
* derive from this class and implement the
* method Output::log(...) to receive logging
* messages.
* \code
* MyOutput log;
* log.subscribe(GetAll());
* \endcode
*/
class SC_SYSTEM_CORE_API Output : public Node {
protected:
Output();
public:
virtual ~Output() {}
public:
/** Subscribe to a particular channel */
bool subscribe(Channel* channel);
bool unsubscribe(Channel* channel);
void logComponent(bool e) { _logComponent = e; }
void logContext(bool e) { _logContext = e; }
void setUTCEnabled(bool e) { _useUTC = e; }
protected:
/** Callback method for receiving log messages */
virtual void log(const char* channelName,
LogLevel level,
const char* msg,
time_t time) = 0;
/** The following methods calls are only valid inside the
log(...) method */
/** Returns the current component name */
const char* component() const;
/** Returns the sourcefile of the current log entry */
const char* fileName() const;
/** Returns the function name of the current log entry */
const char* functionName() const;
/** Returns the line number of the current log entry */
int lineNum() const;
private:
void publish(const Data &data);
protected:
bool _logComponent;
bool _logContext;
bool _useUTC;
private:
PublishLoc* _publisher;
};
}
}
#endif

View File

@ -0,0 +1,102 @@
/***************************************************************************
* 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_PUBLISHER_H
#define SC_LOGGING_PUBLISHER_H
#include <seiscomp/logging/common.h>
#include <seiscomp/logging/node.h>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API Channel;
/*! @class Seiscomp::Logging::Publisher <seiscomp/logging/publisher.h>
@brief Publisher used by log macros.
This derives from Node and interfaces to the static PublishLoc logging
data allowing them to be enabled or disabled depending on subscriber
status.
An instance of this class is created for every error message location.
Normally this class is not used directly.
For example, this
@code
rDebug( "hello world" );
@endcode
is turned approximatly into this:
@code
static PublishLoc _rl = {
pub: 0,
component: "component",
fileName: "myfile.cpp",
functionName: "functionName()",
lineNum: __LINE__,
channel: 0
};
if(_rL.publish != 0)
(*_rl.publish)( &_rL, _RLDebugChannel, "hello world" );
@endcode
The Publisher instance manages the contents of the static structure
_rL. When someone subscribes to it's message, then _rL.publish is set to
point to the publishing function, and when there are no subscribers then
it is set to 0.
The code produced contains one if statement, and with optimization comes
out to about 3 instructions on an x86 computer (not including the
function call). If there are no subscribers to this message then that
is all the overhead, plus the memory usage for the structures
involved and the initial registration when the statement is first
encountered..
@see Channel
@author Valient Gough
*/
class SC_SYSTEM_CORE_API Publisher : public Node {
public:
Publisher();
Publisher(PublishLoc *src);
~Publisher() override;
public:
// metadata about the publisher and its publication
PublishLoc *src;
protected:
void setEnabled(bool newState) override;
Publisher(const Publisher &);
Publisher & operator=(const Publisher &);
};
}
}
#endif

View File

@ -0,0 +1,114 @@
/***************************************************************************
* 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_PUBLISHLOC_H
#define SC_LOGGING_PUBLISHLOC_H
#include <seiscomp/core.h>
#include <fmt/format.h>
#include <fmt/printf.h>
#include <cstdarg>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API Channel;
class SC_SYSTEM_CORE_API Node;
struct SC_SYSTEM_CORE_API PublishLoc {
/*! @struct PublishLoc
@brief Internal RLog structure - static struct for each log() statement
@internal
Structure created for each log location to keep track of logging state
and associated data.
Only static members are initialized at build time, which is why
RLogChannel is passed as argument. Otherwise entire structure will have
to be initialized at run-time which adds extra code and a guard variable
for the struct.
*/
PublishLoc(bool *enabled, const char *component,
const char *fileName, const char *functionName,
int lineNum, Channel *channel);
~PublishLoc();
bool *enabled;
Node *pub;
const char *component;
const char *fileName;
const char *functionName;
int lineNum;
Channel *channel;
inline void enable() { *enabled = true; }
inline void disable() { *enabled = false; }
inline bool isEnabled() { return *enabled; }
};
void Publish(PublishLoc *, Channel *, const char *msg);
void Publish(PublishLoc *, Channel *, const std::string &msg);
template <typename S, typename... Args>
void PublishF(PublishLoc *, Channel *,
const S &format, Args &&...args);
template <typename S, typename... Args>
void PublishP(PublishLoc *, Channel *,
const S &format, Args &&...args);
void VPublish(PublishLoc *, Channel *,
const char *format,
va_list args);
void VPublish(PublishLoc *, Channel *,
fmt::string_view format,
fmt::format_args args);
void VPublish(PublishLoc *, Channel *,
fmt::string_view format,
fmt::printf_args args);
template <typename S, typename... Args>
inline void PublishF(PublishLoc *loc, Channel *channel,
const S &format, Args &&...args) {
VPublish(loc, channel, format, fmt::make_format_args(args...));
}
template <typename S, typename... Args>
inline void PublishP(PublishLoc *loc, Channel *channel,
const S &format, Args &&...args) {
VPublish(loc, channel, format, fmt::make_printf_args(args...));
}
}
}
#endif

View File

@ -0,0 +1,63 @@
/***************************************************************************
* 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_SYSLOG_H
#define SC_LOGGING_SYSLOG_H
#ifndef WIN32
#include <seiscomp/logging/output.h>
namespace Seiscomp {
namespace Logging {
class SC_SYSTEM_CORE_API SyslogOutput : public Output {
public:
SyslogOutput();
SyslogOutput(const char *ident, const char *facility = nullptr);
~SyslogOutput();
int facility() const { return _facility; }
bool open(const char *ident, const char *facility = nullptr);
bool isOpen() const;
void close();
protected:
/** Callback method for receiving log messages */
void log(const char* channelName,
LogLevel level,
const char* msg,
time_t time);
private:
bool _openFlag;
int _facility;
};
}
}
#endif
#endif