mirror of https://gitee.com/bigwinds/arangodb
556 lines
21 KiB
C++
556 lines
21 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/// DISCLAIMER
|
|
///
|
|
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
|
|
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
|
|
///
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
/// you may not use this file except in compliance with the License.
|
|
/// You may obtain a copy of the License at
|
|
///
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
///
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
/// See the License for the specific language governing permissions and
|
|
/// limitations under the License.
|
|
///
|
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
///
|
|
/// @author Achim Brandt
|
|
/// @author Dr. Frank Celler
|
|
///
|
|
/// Portions of the code are:
|
|
///
|
|
/// Copyright (c) 1999, Google Inc.
|
|
/// All rights reserved.
|
|
//
|
|
/// Redistribution and use in source and binary forms, with or without
|
|
/// modification, are permitted provided that the following conditions are
|
|
/// met:
|
|
//
|
|
/// * Redistributions of source code must retain the above copyright
|
|
/// notice, this list of conditions and the following disclaimer.
|
|
/// * Redistributions in binary form must reproduce the above
|
|
/// copyright notice, this list of conditions and the following
|
|
/// disclaimer
|
|
/// in the documentation and/or other materials provided with the
|
|
/// distribution.
|
|
/// * Neither the name of Google Inc. nor the names of its
|
|
/// contributors may be used to endorse or promote products derived
|
|
/// from this software without specific prior written permission.
|
|
///
|
|
/// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
/// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
/// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
/// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
/// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
/// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
/// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
/// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
/// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
/// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
/// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
///
|
|
/// Author: Ray Sidney
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef LIB_BASIC_LOGGER_H
|
|
#define LIB_BASIC_LOGGER_H 1
|
|
|
|
#include "Basics/Common.h"
|
|
|
|
#include <iosfwd>
|
|
#include <sstream>
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief maximal number of log topics
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define MAX_LOG_TOPICS 64
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief logs a message
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define LOG(a) \
|
|
!arangodb::Logger::isEnabled((arangodb::LogLevel::a)) \
|
|
? (void)0 \
|
|
: arangodb::LogVoidify() & (arangodb::LoggerStream() \
|
|
<< (arangodb::LogLevel::a) \
|
|
<< arangodb::Logger::LINE(__LINE__) \
|
|
<< arangodb::Logger::FILE(__FILE__) \
|
|
<< arangodb::Logger::FUNCTION(__FUNCTION__))
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief logs a message for a topic
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define LOG_TOPIC(a, b) \
|
|
!arangodb::Logger::isEnabled((arangodb::LogLevel::a), (b)) \
|
|
? (void)0 \
|
|
: arangodb::LogVoidify() & (arangodb::LoggerStream() \
|
|
<< (arangodb::LogLevel::a) << (b) \
|
|
<< arangodb::Logger::LINE(__LINE__) \
|
|
<< arangodb::Logger::FILE(__FILE__) \
|
|
<< arangodb::Logger::FUNCTION(__FUNCTION__))
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief logs a message given that a condition is true
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define LOG_IF(a, cond) \
|
|
!(arangodb::Logger::isEnabled((arangodb::LogLevel::a)) && (cond)) \
|
|
? (void)0 \
|
|
: arangodb::LogVoidify() & (arangodb::LoggerStream() \
|
|
<< (arangodb::LogLevel::a) \
|
|
<< arangodb::Logger::LINE(__LINE__) \
|
|
<< arangodb::Logger::FILE(__FILE__) \
|
|
<< arangodb::Logger::FUNCTION(__FUNCTION__))
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief logs a message for a topic given that a condition is true
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define LOG_TOPIC_IF(a, b, cond) \
|
|
!(arangodb::Logger::isEnabled((arangodb::LogLevel::a), (b)) && (cond)) \
|
|
? (void)0 \
|
|
: arangodb::LogVoidify() & (arangodb::LoggerStream() \
|
|
<< (arangodb::LogLevel::a) << (b) \
|
|
<< arangodb::Logger::LINE(__LINE__) \
|
|
<< arangodb::Logger::FILE(__FILE__) \
|
|
<< arangodb::Logger::FUNCTION(__FUNCTION__))
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief logs a message every N.the time
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line)
|
|
#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base##line
|
|
|
|
#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__)
|
|
#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__)
|
|
|
|
#define LOG_EVERY_N(a, n) \
|
|
static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
|
|
++LOG_OCCURRENCES; \
|
|
if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
|
|
if (LOG_OCCURRENCES_MOD_N == 1) \
|
|
!(arangodb::Logger::isEnabled((arangodb::LogLevel::a)) && \
|
|
(LOG_OCCURRENCES_MOD_N == 1)) \
|
|
? (void)0 \
|
|
: arangodb::LogVoidify() & (arangodb::LoggerStream() \
|
|
<< (arangodb::LogLevel::a) \
|
|
<< arangodb::Logger::LINE(__LINE__) \
|
|
<< arangodb::Logger::FILE(__FILE__) \
|
|
<< arangodb::Logger::FUNCTION(__FUNCTION__))
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief logs a message for a topic every N.the time
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define LOG_TOPIC_EVERY_N(a, b, n) \
|
|
static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \
|
|
++LOG_OCCURRENCES; \
|
|
if (++LOG_OCCURRENCES_MOD_N > n) LOG_OCCURRENCES_MOD_N -= n; \
|
|
if (LOG_OCCURRENCES_MOD_N == 1) \
|
|
!(arangodb::Logger::isEnabled((arangodb::LogLevel::a), (b)) && \
|
|
(LOG_OCCURRENCES_MOD_N == 1)) \
|
|
? (void)0 \
|
|
: arangodb::LogVoidify() & (arangodb::LoggerStream() \
|
|
<< (arangodb::LogLevel::a) << (b) \
|
|
<< arangodb::Logger::LINE(__LINE__) \
|
|
<< arangodb::Logger::FILE(__FILE__) \
|
|
<< arangodb::Logger::FUNCTION(__FUNCTION__))
|
|
|
|
namespace arangodb {
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief LogLevel
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef TRI_UNDEF_ERR
|
|
#undef ERR
|
|
#endif
|
|
|
|
enum class LogLevel {
|
|
DEFAULT = 0,
|
|
FATAL = 1,
|
|
ERR = 2,
|
|
WARN = 3,
|
|
INFO = 4,
|
|
DEBUG = 5,
|
|
TRACE = 6
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief LogBuffer
|
|
///
|
|
/// This class is used to store a number of log messages in the server
|
|
/// for retrieval. This messages are truncated and overwritten without
|
|
/// warning.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct LogBuffer {
|
|
uint64_t _id;
|
|
LogLevel _level;
|
|
time_t _timestamp;
|
|
char _message[256];
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief LogTopic
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class LogTopic {
|
|
LogTopic& operator=(LogTopic const&) = delete;
|
|
|
|
public:
|
|
explicit LogTopic(std::string const& name);
|
|
|
|
LogTopic(std::string const& name, LogLevel level);
|
|
|
|
LogTopic(LogTopic const& that) noexcept : _id(that._id), _name(that._name) {
|
|
_level.store(that._level, std::memory_order_relaxed);
|
|
}
|
|
|
|
LogTopic(LogTopic&& that) noexcept : _id(that._id), _name(that._name) {
|
|
_level.store(that._level, std::memory_order_relaxed);
|
|
}
|
|
|
|
public:
|
|
size_t id() const { return _id; }
|
|
std::string const& name() const { return _name; }
|
|
LogLevel level() const { return _level.load(std::memory_order_relaxed); }
|
|
|
|
void setLogLevel(LogLevel level) {
|
|
_level.store(level, std::memory_order_relaxed);
|
|
}
|
|
|
|
private:
|
|
size_t _id;
|
|
std::string _name;
|
|
std::atomic<LogLevel> _level;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief Logger
|
|
///
|
|
/// This class provides various static members which can be used as logging
|
|
/// streams. Output to the logging stream is appended by using the operator <<,
|
|
/// as soon as a line is completed, an implicit endl will be used to flush the
|
|
/// stream. Each line of output is prefixed by some informational data.
|
|
///
|
|
///
|
|
/// options:
|
|
/// log.level info
|
|
/// log.level compactor=debug
|
|
/// log.level replication=trace
|
|
///
|
|
/// log.output compactor=file:/a/b/c
|
|
/// log.output replication=syslog:xxxx
|
|
/// log.output performance=+
|
|
/// log.output file:/c/d/ef
|
|
///
|
|
/// deprecated:
|
|
///
|
|
/// log.file x => log.output file:x
|
|
/// log.requests-file y => log.output requests=file:y
|
|
/// log.performance => log.level performance=info
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class Logger {
|
|
Logger(Logger const&) = delete;
|
|
Logger& operator=(Logger const&) = delete;
|
|
|
|
friend class LoggerStream;
|
|
|
|
public:
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief predefined topics
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LogTopic COLLECTOR;
|
|
static LogTopic COMPACTOR;
|
|
static LogTopic MMAP;
|
|
static LogTopic PERFORMANCE;
|
|
static LogTopic QUERIES;
|
|
static LogTopic REPLICATION;
|
|
static LogTopic REQUESTS;
|
|
static LogTopic DATAFILES;
|
|
static LogTopic THREADS;
|
|
|
|
public:
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief duration
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct DURATION {
|
|
explicit DURATION(double duration, int precision = 6)
|
|
: _duration(duration), _precision(precision){};
|
|
double _duration;
|
|
int _precision;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief range
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct RANGE {
|
|
RANGE(void const* baseAddress, size_t size)
|
|
: baseAddress(baseAddress), size(size){};
|
|
void const* baseAddress;
|
|
size_t size;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief line number helper class
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct LINE {
|
|
explicit LINE(long int line) : _line(line){};
|
|
long int _line;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief filename helper class
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct FILE {
|
|
explicit FILE(char const* file) : _file(file){};
|
|
char const* _file;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief function helper class
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct FUNCTION {
|
|
explicit FUNCTION(char const* function) : _function(function){};
|
|
char const* _function;
|
|
};
|
|
|
|
public:
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief creates a new appender
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void addAppender(std::string const&, bool, std::string const&, std::unordered_set<std::string>&);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief determines the global log level
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static LogLevel logLevel();
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief determines the log levels of the topics
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::vector<std::pair<std::string, LogLevel>> logLevelTopics();
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets the global log level
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void setLogLevel(LogLevel);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets the log level from a string
|
|
///
|
|
/// set the global level: info
|
|
/// set a topic level: performance=info
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void setLogLevel(std::string const&);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets the log level from a vector of string
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void setLogLevel(std::vector<std::string> const&);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets the output prefix
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void setOutputPrefix(std::string const&);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets the line number mode
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void setShowLineNumber(bool);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets the thread identifier mode
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void setShowThreadIdentifier(bool);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief sets the local time mode
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void setUseLocalTime(bool);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns a string description for the log level
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::string const& translateLogLevel(LogLevel);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks if logging is enabled for log level
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool isEnabled(LogLevel level) {
|
|
return (int)level <= (int)_level.load(std::memory_order_relaxed);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief checks if logging is enabled for log topic
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool isEnabled(LogLevel level, LogTopic const& topic) {
|
|
return (int)level <= (int)((topic.level() == LogLevel::DEFAULT)
|
|
? _level.load(std::memory_order_relaxed)
|
|
: topic.level());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief returns the last log entries
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::vector<LogBuffer> bufferedEntries(LogLevel level, uint64_t start,
|
|
bool upToLevel);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief initializes the logging component
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void initialize(bool);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief shuts down the logging components
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void shutdown(bool);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief reopens all log appenders
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void reopen();
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief tries to flush the logging
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void flush();
|
|
|
|
private:
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
/// @brief current log level
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static std::atomic<LogLevel> _level;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief LoggerStream
|
|
///
|
|
/// Helper acting as a output stream.
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class LoggerStream {
|
|
LoggerStream(LoggerStream const&) = delete;
|
|
LoggerStream& operator=(LoggerStream const&) = delete;
|
|
|
|
public:
|
|
LoggerStream()
|
|
: _topicId(MAX_LOG_TOPICS),
|
|
_level(LogLevel::DEFAULT),
|
|
_line(0),
|
|
_file(nullptr),
|
|
_function(nullptr) {}
|
|
|
|
~LoggerStream();
|
|
|
|
public:
|
|
LoggerStream& operator<<(LogLevel level) {
|
|
_level = level;
|
|
return *this;
|
|
}
|
|
|
|
LoggerStream& operator<<(LogTopic topic) {
|
|
_topicId = topic.id();
|
|
_out << "{" + topic.name() << "} ";
|
|
return *this;
|
|
}
|
|
|
|
LoggerStream& operator<<(Logger::RANGE range);
|
|
|
|
LoggerStream& operator<<(Logger::DURATION duration);
|
|
|
|
LoggerStream& operator<<(Logger::LINE line) {
|
|
_line = line._line;
|
|
return *this;
|
|
}
|
|
|
|
LoggerStream& operator<<(Logger::FILE file) {
|
|
_file = file._file;
|
|
return *this;
|
|
}
|
|
|
|
LoggerStream& operator<<(Logger::FUNCTION function) {
|
|
_function = function._function;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
LoggerStream& operator<<(T obj) {
|
|
_out << obj;
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
LoggerStream& operator<<(std::vector<T> const& v) {
|
|
for (auto const& i : v)
|
|
_out << i << " ";
|
|
return *this;
|
|
}
|
|
|
|
template <typename T>
|
|
LoggerStream& operator<<(std::unordered_set<T> const& us) {
|
|
for (auto const& i : us)
|
|
_out << i;
|
|
return *this;
|
|
}
|
|
|
|
private:
|
|
std::stringstream _out;
|
|
size_t _topicId;
|
|
LogLevel _level;
|
|
long int _line;
|
|
char const* _file;
|
|
char const* _function;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// @brief helper class for macros
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
class LogVoidify {
|
|
public:
|
|
LogVoidify() {}
|
|
void operator&(LoggerStream const&) {}
|
|
};
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream&, arangodb::LogLevel);
|
|
|
|
#endif
|