MXS-2005: Move Logger into maxutils

Moved the logger into the maxutils library as it is a generic
utility. Also moved mxs_strerror into it as it depends on it.
This commit is contained in:
Markus Mäkelä
2018-08-13 15:50:05 +03:00
parent dc2578ed98
commit c543525c1b
6 changed files with 49 additions and 25 deletions

View File

@ -22,7 +22,6 @@ add_library(maxscale-common SHARED
listener.cc
load_utils.cc
log_manager.cc
logger.cc
mariadb.cc
maxscale_pcre2.cc
misc.cc

View File

@ -1,171 +0,0 @@
#pragma once
/*
* Copyright (c) 2016 MariaDB Corporation Ab
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
*
* Change Date: 2022-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#include <maxscale/ccdefs.hh>
#include <string>
#include <mutex>
#include <memory>
#include <unistd.h>
namespace maxscale
{
// Minimal logger interface
class Logger
{
public:
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
virtual ~Logger()
{
}
/**
* Write a message to the log
*
* @param msg Message to write
* @param len Length of message
*
* @return True on success
*/
virtual bool write(const char* msg, int len) = 0;
/**
* Rotate the logfile
*
* @return True if the log was rotated
*/
virtual bool rotate() = 0;
/**
* Get the name of the log file
*
* @return The name of the log file
*/
const char* filename() const
{
return m_filename.c_str();
}
protected:
Logger(const std::string& filename):
m_filename(filename)
{
}
std::string m_filename;
};
class FileLogger: public Logger
{
public:
FileLogger(const FileLogger&) = delete;
FileLogger& operator=(const FileLogger&) = delete;
/**
* Create a new logger that writes to a file
*
* @param logdir Log file to open
*
* @return New logger instance or an empty unique_ptr on error
*/
static std::unique_ptr<Logger> create(const std::string& filename);
/**
* Close the log
*
* A footer is written to the log and the file is closed.
*/
~FileLogger();
/**
* Write a message to the log
*
* @param msg Message to write
* @param len Length of message
*
* @return True on success
*/
bool write(const char* msg, int len);
/**
* Rotate the logfile by reopening it
*
* @return True if the log was rotated. False if the opening of the new file
* descriptor failed in which case the old file descriptor will be used.
*/
bool rotate();
private:
int m_fd;
std::mutex m_lock;
FileLogger(int fd, const std::string& filename);
bool write_header();
bool write_footer(const char* suffix);
void close(const char* msg);
};
class StdoutLogger: public Logger
{
public:
StdoutLogger(const StdoutLogger&) = delete;
StdoutLogger& operator=(const StdoutLogger&) = delete;
/**
* Create a new logger that writes to stdout
*
* @param logdir Log file to open, has no functional effect on this logger
*
* @return New logger instance or an empty unique_ptr on error
*/
static std::unique_ptr<Logger> create(const std::string& filename)
{
return std::unique_ptr<Logger>(new StdoutLogger(filename));
}
/**
* Write a message to stdout
*
* @param msg Message to write
* @param len Length of message
*
* @return True on success
*/
bool write(const char* msg, int len)
{
return ::write(STDOUT_FILENO, msg, len) != -1;
}
/**
* Rotate the "logfile"
*
* @return Always true
*/
bool rotate()
{
return true;
};
private:
StdoutLogger(const std::string& filename):
Logger(filename)
{
}
};
}

View File

@ -21,17 +21,16 @@
#include <string>
#include <mutex>
#include <maxbase/error.h>
#include <maxbase/logger.hh>
#include <maxscale/config.h>
#include <maxscale/debug.h>
#include <maxscale/json_api.h>
#include <maxscale/session.h>
#include <maxscale/utils.h>
#include "internal/logger.hh"
using namespace maxscale;
static std::unique_ptr<Logger> logger;
static std::unique_ptr<mxb::Logger> logger;
const std::string LOGFILE_NAME = "maxscale.log";
@ -329,11 +328,11 @@ bool mxs_log_init(const char* ident, const char* logdir, mxs_log_target_t target
{
case MXS_LOG_TARGET_FS:
case MXS_LOG_TARGET_DEFAULT:
logger = FileLogger::create(filename);
logger = mxb::FileLogger::create(filename);
break;
case MXS_LOG_TARGET_STDOUT:
logger = StdoutLogger::create(filename);
logger = mxb::StdoutLogger::create(filename);
break;
default:
@ -864,13 +863,7 @@ int mxs_log_message(int priority,
const char* mxs_strerror(int error)
{
static thread_local char errbuf[MXS_STRERROR_BUFLEN];
#ifdef HAVE_GLIBC
return strerror_r(error, errbuf, sizeof(errbuf));
#else
strerror_r(error, errbuf, sizeof(errbuf));
return errbuf;
#endif
return mxb_strerror(error);
}
json_t* get_log_priorities()

View File

@ -1,237 +0,0 @@
/*
* Copyright (c) 2016 MariaDB Corporation Ab
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
*
* Change Date: 2022-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#include "internal/logger.hh"
#include <syslog.h>
#include <fcntl.h>
#include <unistd.h>
#include <chrono>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <maxscale/debug.h>
/**
* Error logging for the logger itself.
*
* For obvious reasons, it cannot use its own functions for reporting errors.
*/
#define LOG_ERROR(format, ...) do { fprintf(stderr, format, ##__VA_ARGS__); } while (false)
//
// Helper functions
//
namespace
{
int open_fd(const std::string& filename)
{
int fd = open(filename.c_str(), O_WRONLY | O_APPEND | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
if (fd == -1)
{
LOG_ERROR("Failed to open file '%s': %d, %s\n", filename.c_str(), errno, mxs_strerror(errno));
}
return fd;
}
bool should_log_error()
{
using std::chrono::seconds;
static auto last_write = std::chrono::steady_clock::now() - seconds(61);
auto now = std::chrono::steady_clock::now();
bool rval = false;
if ((now - last_write).count() >= 60)
{
last_write = now;
rval = true;
}
return rval;
}
}
namespace maxscale
{
//
// Public methods
//
std::unique_ptr<Logger> FileLogger::create(const std::string& filename)
{
std::unique_ptr<FileLogger> logger;
int fd = open_fd(filename);
if (fd != -1)
{
logger.reset(new (std::nothrow) FileLogger(fd, filename));
if (logger)
{
logger->write_header();
}
else
{
::close(fd);
}
}
return std::move(logger);
}
FileLogger::~FileLogger()
{
std::lock_guard<std::mutex> guard(m_lock);
ss_dassert(m_fd != -1);
close("MariaDB MaxScale is shut down.");
}
bool FileLogger::write(const char* msg, int len)
{
bool rval = true;
std::lock_guard<std::mutex> guard(m_lock);
while (len > 0)
{
int rc;
do
{
rc = ::write(m_fd, msg, len);
}
while (rc == -1 && errno == EINTR);
if (rc == -1)
{
if (should_log_error()) // Coarse error suppression
{
LOG_ERROR("Failed to write to log: %d, %s\n", errno, mxs_strerror(errno));
}
rval = false;
break;
}
// If write only writes a part of the message, retry again
len -= rc;
msg += rc;
}
return rval;
}
bool FileLogger::rotate()
{
std::lock_guard<std::mutex> guard(m_lock);
int fd = open_fd(m_filename);
if (fd != -1)
{
close("File closed due to log rotation.");
m_fd = fd;
}
return fd != -1;
}
//
// Private methods
//
FileLogger::FileLogger(int fd, const std::string& filename):
Logger(filename),
m_fd(fd)
{
}
void FileLogger::close(const char* msg)
{
write_footer(msg);
::close(m_fd);
m_fd = -1;
}
// Nearly identical to the one in log_manager.cc
bool FileLogger::write_header()
{
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
const char PREFIX[] = "MariaDB MaxScale "; // sizeof(PREFIX) includes the NULL.
char time_string[32]; // 26 would be enough, according to "man asctime".
asctime_r(&tm, time_string);
size_t size = sizeof(PREFIX) + m_filename.length() + 2 * sizeof(' ') + strlen(time_string);
char header[size + 2]; // For the 2 newlines.
sprintf(header, "\n\n%s%s %s", PREFIX, m_filename.c_str(), time_string);
char line[sizeof(header) - 1];
memset(line, '-', sizeof(line) - 1);
line[sizeof(line) - 1] = '\n';
bool ok = ::write(m_fd, header, sizeof(header) - 1) != -1 &&
::write(m_fd, line, sizeof(line)) != -1;
if (!ok)
{
LOG_ERROR("Error: Writing log header failed due to %d, %s\n",
errno, mxs_strerror(errno));
}
return ok;
}
// Nearly identical to the one in log_manager.cc
bool FileLogger::write_footer(const char* suffix)
{
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
const char FORMAT[] = "%04d-%02d-%02d %02d:%02d:%02d";
char time_string[20]; // 19 chars + NULL.
sprintf(time_string, FORMAT,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
size_t size = sizeof(time_string) + 3 * sizeof(' ') + strlen(suffix) + sizeof('\n');
char header[size];
sprintf(header, "%s %s\n", time_string, suffix);
char line[sizeof(header) - 1];
memset(line, '-', sizeof(line) - 1);
line[sizeof(line) - 1] = '\n';
bool ok = ::write(m_fd, header, sizeof(header) - 1) != -1 &&
::write(m_fd, line, sizeof(line)) != -1;
if (!ok)
{
LOG_ERROR("Error: Writing log footer failed due to %d, %s\n",
errno, mxs_strerror(errno));
}
return ok;
}
}