仿muduo日志库:c++小巧日志库实现
#pragma once
#include <iostream>
#include <chrono>
#include <string.h>
#include "log_stream.h"
class Logger
{
public:
enum LogLevel
{
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
FATAL,
NUM_LOG_LEVELS,
};
class SourceFile
{
public:
template<int N>
inline SourceFile(const char(&arr)[N])
:m_data(arr),
m_size(N - 1)
{
const char* slash = strrchr(m_data, '/');
if (slash)
{
m_data = slash + 1;
m_size -= static_cast<int>(m_data - arr);
}
}
explicit SourceFile(const char* filename)
: m_data(filename)
{
const char* slash = strrchr(filename, '/');
if (slash)
{
m_data = slash + 1;
}
m_size = static_cast<int>(strlen(m_data));
}
const char* m_data;
int m_size;
};
Logger(SourceFile p_file, int p_nline);
Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel);
Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel, const char* p_func);
Logger(SourceFile p_file, int p_nline, bool p_btoAbort);
~Logger();
static void setLogLevel(LogLevel p_enumLevel);
static LogLevel logLevel();
LogStream& stream() { return m_impl.m_stream; }
typedef void (*outputFunc)(const char* msg, int len);
typedef void (*flushFunc)();
static void setOutput(outputFunc);
static void setFlush(flushFunc);
private:
Logger(const Logger& lg);
Logger& operator=(const Logger& lg);
class Impl
{
public:
typedef Logger::LogLevel LogLevel;
Impl(LogLevel p_enumLevel, int p_nOldErrno, const SourceFile& p_file, int p_nline);
void formatTime();
void finish();
std::chrono::system_clock::time_point m_time;
LogStream m_stream;
LogLevel m_level;
int m_line;
SourceFile m_fileBaseName;
};
Impl m_impl;
};
#define log_trace if (Logger::logLevel() <= Logger::TRACE) Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream()
#define log_info if (Logger::logLevel() <= Logger::INFO) Logger(__FILE__, __LINE__).stream()
#define log_warn Logger(__FILE__, __LINE__, Logger::WARN).stream()
#define log_debug Logger(__FILE__, __LINE__, Logger::DEBUG).stream()
#define log_error Logger(__FILE__, __LINE__, Logger::ERROR).stream()
#define log_fatal Logger(__FILE__, __LINE__, Logger::FATAL).stream()
#define log_syserr Logger(__FILE__, __LINE__, false).stream()
#define log_sysfatal Logger(__FILE__, __LINE__, true).stream()
#define _CRT_SECURE_NO_WARNINGS
#include <time.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include "logger.h"
#include <ctime>
#include <sstream>
Logger::LogLevel g_logLevel = Logger::INFO;
void Logger::setLogLevel(LogLevel p_enumLevel)
{
g_logLevel = p_enumLevel;
}
Logger::LogLevel Logger::logLevel()
{
return g_logLevel;
}
const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
{
"[TRACE]",
"[DEBUG]",
"[INFO ]",
"[WARN ]",
"[ERROR]",
"[FATAL]",
};
class T
{
public:
T(const char* str, unsigned len)
:m_str(str),
m_len(len)
{
assert(strlen(str) == m_len);
}
const char* m_str;
const unsigned m_len;
};
void defaultOutput(const char* msg, int len)
{
size_t n = fwrite(msg, 1, len, stdout);
(void)n;
}
void defaultFlush() {
fflush(stdout);
}
Logger::outputFunc g_output = defaultOutput;
Logger::flushFunc g_flush = defaultFlush;
void Logger::setOutput(outputFunc out)
{
g_output = out;
}
void Logger::setFlush(flushFunc flush)
{
g_flush = flush;
}
Logger::Logger(SourceFile p_file, int p_nline)
: m_impl(INFO, 0, p_file, p_nline)
{
}
Logger::Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel)
: m_impl(p_enumLevel, 0, p_file, p_nline)
{
}
Logger::Logger(SourceFile p_file, int p_nline, bool p_btoAbort)
: m_impl(p_btoAbort ? FATAL : ERROR, errno, p_file, p_nline)
{
}
Logger::Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel, const char* p_func)
: m_impl(p_enumLevel, 0, p_file, p_nline)
{
m_impl.m_stream << '[' << p_func << "] ";
}
Logger::~Logger()
{
m_impl.finish();
const LogStream::Buffer& buf(stream().buffer());
g_output(buf.data(), buf.length());
if (m_impl.m_level == FATAL)
{
g_flush();
}
}
Logger::Impl::Impl(LogLevel p_enumLevel, int p_nOldErrno, const SourceFile& p_file, int p_nline)
: m_time(std::chrono::system_clock::now()),
m_stream(),
m_level(p_enumLevel),
m_fileBaseName(p_file),
m_line(p_nline)
{
formatTime();
m_stream << LogLevelName[p_enumLevel] << ' ';
m_stream << '[' << m_fileBaseName.m_data << ':' << m_line << "] ";
std::ostringstream oss;
oss << std::this_thread::get_id();
m_stream << '[' << oss.str().c_str() << "] ";
if (p_nOldErrno != 0)
{
m_stream << " (errno=" << p_nOldErrno << ") ";
}
}
void Logger::Impl::finish()
{
m_stream << 'n';
}
void Logger::Impl::formatTime()
{
auto tt = std::chrono::system_clock::to_time_t(m_time);
struct tm* ptm = localtime(&tt);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(m_time.time_since_epoch()) % 1000;
auto cs = std::chrono::duration_cast<std::chrono::microseconds>(m_time.time_since_epoch()) % 1000000;
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(m_time.time_since_epoch()) % 1000000000;
char date[128] = { 0 };
sprintf(date, "[%d-%02d-%02d %02d:%02d:%02d:%03ld:%03ld:%03ld] ",
(int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday,
(int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec, ms.count(), cs.count() % 1000, ns.count() % 1000);
m_stream << date;
}
#pragma once
#include <stdio.h>
#include <string.h>
#include <thread>
const int kSmallBuffer = 4096;
const int kLargeBuffer = 4096;
template<int SIZE>
class LogBuffer
{
public:
LogBuffer() : m_cur(m_data) {}
~LogBuffer() {}
void append(const char* p_chBuf, size_t p_nlen)
{
if ((avail()) > p_nlen)
{
memcpy(m_cur, p_chBuf, p_nlen);
m_cur += p_nlen;
}
}
char* current() { return m_cur; };
int avail() const { return static_cast<int> (end() - m_cur); }
void add(size_t p_nlen) { m_cur += p_nlen; }
int length() const { return m_cur - m_data; }
const char* data() const { return m_data; }
private:
const char* end() const { return m_data + sizeof(m_data); }
char m_data[SIZE];
char* m_cur;
};
class LogStream
{
public:
LogStream();
~LogStream();
using Buffer = LogBuffer<kSmallBuffer>;
using self = LogStream;
self& operator<<(bool v);
self& operator<<(short);
self& operator<<(unsigned short);
self& operator<<(int);
self& operator<<(unsigned int);
self& operator<<(long);
self& operator<<(unsigned long);
self& operator<<(long long);
self& operator<<(unsigned long long);
self& operator<<(const void*);
self& operator<<(float v);
self& operator<<(double);
self& operator<<(char v);
self& operator<<(const char*);
void append(const char* p_chData, int p_nlen) { return m_buffer.append(p_chData, p_nlen); }
const Buffer& buffer() const { return m_buffer; }
private:
LogStream(const LogStream& ls);
LogStream& operator=(const LogStream& ls);
template<typename T>
void formatInteger(T v);
Buffer m_buffer;
static const int kMaxNumericSize = 32;
};
class Fmt
{
public:
template<typename T>
Fmt(const char* fmt, T val);
const char* data() const { return m_buf; }
int length() const { return m_length; }
private:
char m_buf[32];
int m_length;
};
inline LogStream& operator<<(LogStream& p_stLog, const Fmt& p_fmt)
{
p_stLog.append(p_fmt.data(), p_fmt.length());
return p_stLog;
}
#include <stdio.h>
#include <assert.h>
#include <algorithm>
#include "log_stream.h"
LogStream::LogStream() {}
LogStream::~LogStream() {}
LogStream& LogStream::operator<<(bool v)
{
m_buffer.append(v ? "1" : "0", 1);
return *this;
}
LogStream& LogStream::operator<<(short v)
{
*this << static_cast<int>(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned short v)
{
*this << static_cast<unsigned int>(v);
return *this;
}
LogStream& LogStream::operator<<(int v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned int v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(long long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(unsigned long long v)
{
formatInteger(v);
return *this;
}
LogStream& LogStream::operator<<(const void*)
{
printf("undefinen");
return *this;
}
LogStream& LogStream::operator<<(float v)
{
*this << static_cast<double>(v);
return *this;
}
LogStream& LogStream::operator<<(double v)
{
if (m_buffer.avail() >= kMaxNumericSize)
{
int len = snprintf(m_buffer.current(), kMaxNumericSize, "%.12g", v);
m_buffer.add(len);
}
return *this;
}
LogStream& LogStream::operator<<(char v)
{
m_buffer.append(&v, 1);
return *this;
}
LogStream& LogStream::operator<<(const char* str)
{
if (str)
{
m_buffer.append(str, strlen(str));
}
else
{
m_buffer.append("(NULL)", 6);
}
return *this;
}
const char digits[] = "9876543210123456789";
const char* zero = digits + 9;
template<typename T>
size_t convert(char buf[], T value)
{
T i = value;
char* p = buf;
do
{
int lsd = static_cast<int>(i % 10);
i /= 10;
*p++ = zero[lsd];
} while (i != 0);
if (value < 0)
{
*p++ = '-';
}
*p = '