libreoffice-online/loolwsd/Log.cpp
Tor Lillqvist 8c404e700e Add FIXME about systemd logging mechanism considerations
If we can find out that we are running under systemd, we probably
shouldn't bother with any timestamps in our logging. Systemd does
that, doesn't it?
2016-09-27 15:53:48 +03:00

191 lines
5.4 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <sys/prctl.h>
#include <atomic>
#include <cassert>
#include <iomanip>
#include <sstream>
#include <string>
#include <sys/syscall.h>
#include <unistd.h>
#include <Poco/ConsoleChannel.h>
#include <Poco/FileChannel.h>
#include <Poco/FormattingChannel.h>
#include <Poco/PatternFormatter.h>
#include <Poco/Process.h>
#include <Poco/SplitterChannel.h>
#include <Poco/Thread.h>
#include <Poco/Timestamp.h>
#include "Log.hpp"
static char LogPrefix[256] = { '\0' };
namespace Log
{
using namespace Poco;
static const Poco::Int64 epochStart = Poco::Timestamp().epochMicroseconds();
/// Helper to avoid destruction ordering issues.
struct StaticNames {
std::atomic<bool> inited;
std::string name;
std::string id;
StaticNames() :
inited(true)
{
}
~StaticNames()
{
inited = false;
}
};
static StaticNames Source;
// We need a signal safe means of writing messages
// $ man 7 signal
void signalLog(const char *message)
{
while (true) {
int length = strlen(message);
int written = write (STDERR_FILENO, message, length);
if (written < 0)
{
if (errno == EINTR)
continue; // ignore.
else
break;
}
message += written;
if (message[0] == '\0')
break;
}
}
static void getPrefix(char *buffer, const char* level)
{
// FIXME: If running under systemd it is redundant to output timestamps, as those will be
// attached to messages that the systemd journalling mechanism picks up anyway, won't they?
Poco::Int64 usec = Poco::Timestamp().epochMicroseconds() - epochStart;
const Poco::Int64 one_s = 1000000;
const Poco::Int64 hours = usec / (one_s*60*60);
usec %= (one_s*60*60);
const Poco::Int64 minutes = usec / (one_s*60);
usec %= (one_s*60);
const Poco::Int64 seconds = usec / (one_s);
usec %= (one_s);
char procName[32]; // we really need only 16
if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(procName), 0, 0, 0) != 0)
strncpy(procName, "<noid>", sizeof(procName) - 1);
const char *appName = (Source.inited ? Source.id.c_str() : "<shutdown>");
assert(strlen(appName) + 32 + 28 < 1024 - 1);
snprintf(buffer, 4095, "%s-%.04lu %d:%.2d:%.2d.%.6d [ %s ] %s ", appName,
syscall(SYS_gettid),
(int)hours, (int)minutes, (int)seconds, (int)usec,
procName, level);
}
std::string prefix(const char* level)
{
char buffer[1024];
getPrefix(buffer, level);
return std::string(buffer);
}
void signalLogPrefix()
{
char buffer[1024];
getPrefix(buffer, "SIG");
signalLog(buffer);
}
void initialize(const std::string& name,
const std::string& logLevel,
const bool withColor,
const bool logToFile,
std::map<std::string, std::string> config)
{
Source.name = name;
std::ostringstream oss;
oss << Source.name << '-'
<< std::setw(5) << std::setfill('0') << Poco::Process::id();
Source.id = oss.str();
assert (sizeof (LogPrefix) > strlen(oss.str().c_str()) + 1);
strncpy(LogPrefix, oss.str().c_str(), sizeof(LogPrefix));
// Configure the logger.
AutoPtr<Channel> channel;
if (logToFile)
{
channel = static_cast<Poco::Channel*>(new FileChannel("loolwsd.log"));
for (const auto& pair : config)
{
channel->setProperty(pair.first, pair.second);
}
}
else if (withColor)
channel = static_cast<Poco::Channel*>(new Poco::ColorConsoleChannel());
else
channel = static_cast<Poco::Channel*>(new Poco::ConsoleChannel());
auto& logger = Poco::Logger::create(Source.name, channel, Poco::Message::PRIO_TRACE);
logger.setLevel(logLevel.empty() ? std::string("trace") : logLevel);
info("Initializing " + name);
info("Log level is [" + std::to_string(logger.getLevel()) + "].");
}
Poco::Logger& logger()
{
return Poco::Logger::get(Source.inited ? Source.name : std::string());
}
void trace(const std::string& msg)
{
logger().trace(prefix("TRC") + msg);
}
void debug(const std::string& msg)
{
logger().debug(prefix("DBG") + msg);
}
void info(const std::string& msg)
{
logger().information(prefix("INF") + msg);
}
void warn(const std::string& msg)
{
logger().warning(prefix("WRN") + msg);
}
void error(const std::string& msg)
{
logger().error(prefix("ERR") + msg);
}
void syserror(const std::string& msg)
{
logger().error(prefix("SYS") + msg + " (errno: " + std::string(std::strerror(errno)) + ")");
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */