spdlogwarp.cpp 6.9 KB
/*
 *
 *  Created on: 2020-12-13
 *      Author: liuhang
 */

//fmtlib https://fmt.dev/latest/api.html#format-api

#include "spdlog/spdlogwarp.hh"
#include <stdarg.h>
#include <iostream>
#include <sstream>
#include <chrono>
#include <mutex>
#include "spdlog/fmt/fmt.h"


#define _SPD_FORMAT_ "%Y-%m-%d %H:%M:%S.%e%z|%l|[%s:%#:%t] %v"
#define _SPD_FORMAT_2 "%Y-%m-%d %H:%M:%S.%e%z|{}|{}|%l|[%s:%#:%t] %v"
std::shared_ptr<spdlog::logger> SLog::m_globalLog;
std::map<std::string, std::shared_ptr<spdlog::logger>> SLog::m_trace;
std::map<std::string, std::shared_ptr<spdlog::logger>> SLog::m_loggers;
std::string SLog::m_logdir;
std::string SLog::m_appname;
std::string SLog::m_lastymd = "";
std::atomic<int> SLog::m_state(0);
bool SLog::m_inited = false;
std::mutex SLog::m_lock;

void cslog(const char *text)
{
  SLog::global()->info(text);
}

std::string SLog::getymd()
{
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  time_t tt = std::chrono::system_clock::to_time_t(now);
  tm utc_tm = *gmtime(&tt);
  tm local_tm = *localtime(&tt);
  return fmt::format("{:04}-{:02}-{:02}-{:02}", 1900+local_tm.tm_year, local_tm.tm_mon + 1, local_tm.tm_mday, local_tm.tm_min);
}


static std::string get_before_ymd(int days)
{
  std::chrono::duration<int, std::ratio<60 * 60 * 24>> nday(7);
  std::chrono::system_clock::time_point before =
      std::chrono::system_clock::now() - nday;

  time_t tt = std::chrono::system_clock::to_time_t(before);
  tm utc_tm = *gmtime(&tt);
  tm local_tm = *localtime(&tt);
  return fmt::format("{:04}-{:02}-{:02}-{:02}", 1900+local_tm.tm_year, local_tm.tm_mon + 1, local_tm.tm_mday, local_tm.tm_min);
}
static std::string getext(const std::string &appname)
{
  if(appname.find(".log") == std::string::npos && appname.find(".txt") == std::string::npos)
    return ".log";
  else
    return "";
}

void SLog::makesure_dir(const std::string &path)
{
  std::string dirstr = path;
  DIR *dirptr = opendir(dirstr.c_str());
  if (dirptr == NULL) {
    int ret = mkdir(dirstr.c_str(), (S_IRWXU | S_IRWXG | S_IRWXO));
    if (ret == 0) {
    } else {
    }
  }
  else
  {
    closedir(dirptr);
  }
}

void SLog::monitor_thread() {
  while (1) {
    std::string curymd = getymd();
    if (curymd != m_lastymd) {
      m_state = 1;
      printf("spdlog::drop_all() ymd:%s, m_lastymd:%s", curymd.c_str(), m_lastymd.c_str());
      m_lastymd = curymd;
      spdlog::drop_all();
      m_loggers.clear();
      m_trace.clear();

      auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
      console_sink->set_level(spdlog::level::debug);
      std::string logname = m_logdir + "/" + getymd() + "/" + m_appname + getext(m_appname);
      auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logname, LOG_SIZE, 100);
      file_sink->set_level(spdlog::level::debug);

      auto globallog = std::shared_ptr<spdlog::logger>(new spdlog::logger(m_appname, {console_sink, file_sink}));
      m_globalLog.swap(globallog);
      m_globalLog->set_level(spdlog::level::debug);
      spdlog::set_pattern(_SPD_FORMAT_);
      m_globalLog->set_pattern(fmt::format(_SPD_FORMAT_2, m_appname, "global"));
      m_globalLog->info("rebuild spdlog success");
      set_default_logger(m_globalLog);

      m_state = 0;
    }
    std::this_thread::sleep_for(std::chrono::seconds(5));
  }
}

void SLog::init(const std::string &logdir, const std::string &appname)
{
  m_logdir = logdir;
  m_state = 0;
  m_appname = appname;
  makesure_dir(logdir);
  makesure_dir(logdir + "/" + getymd());
  m_lastymd = getymd();
  std::thread th = std::thread(monitor_thread);
  th.detach();
  auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
  console_sink->set_level(spdlog::level::debug);
  std::string logname = logdir + "/" + getymd() + "/" + appname + getext(appname);
  auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logname, LOG_SIZE, 100);
  file_sink->set_level(spdlog::level::debug);
  m_globalLog = std::shared_ptr<spdlog::logger>(new spdlog::logger(appname, {console_sink, file_sink}));
  m_globalLog->set_level(spdlog::level::debug);
  spdlog::set_pattern(_SPD_FORMAT_);
  m_globalLog->set_pattern(fmt::format(_SPD_FORMAT_2, appname, "global"));
  m_globalLog->info("init spdlog success");
  set_default_logger(m_globalLog);
  spdlog::flush_every(std::chrono::seconds(1));
  m_inited = true;
}

std::shared_ptr<spdlog::logger> SLog::get(const std::string &name)
{
  while(m_state)
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  std::shared_ptr<spdlog::logger> _logger;
  std::lock_guard<std::mutex> autolock(m_lock);
  auto iter = m_loggers.find(name);
  if (iter == m_loggers.end())
  {
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::debug);
    makesure_dir(m_logdir + "/" + getymd());
    std::string logname = m_logdir + "/" + getymd() + "/" + name + getext(name);
    auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logname, LOG_SIZE, 300);
    file_sink->set_level(spdlog::level::debug);
    _logger = std::shared_ptr<spdlog::logger>(new spdlog::logger(name, {console_sink, file_sink}));
    _logger->set_pattern(fmt::format(_SPD_FORMAT_2, m_appname, name));
    spdlog::register_logger(_logger);
    m_loggers[name] = _logger;
  }
  else
  {
    _logger = iter->second;
  }
  return _logger;
}

std::shared_ptr<spdlog::logger> SLog::get_trace(const std::string &name)
{
  while(m_state)
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  std::shared_ptr<spdlog::logger> _logger;
  auto iter = m_trace.find(name);
  if (iter == m_trace.end())
  {
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    // console_sink->set_level(spdlog::level::debug);
    makesure_dir(m_logdir + "/" + getymd());
    std::string logname = m_logdir + "/" + getymd() + "/" + name + getext(name);
    auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logname, LOG_SIZE, 100);
    // file_sink->set_level(spdlog::level::debug);
    _logger = std::shared_ptr<spdlog::logger>(new spdlog::logger(name, {console_sink, file_sink}));
    _logger->set_pattern(fmt::format(_SPD_FORMAT_2, m_appname, name));
    _logger->enable_backtrace(512);
    m_trace[name] = _logger;
    m_globalLog->info("add new trace name:{}", name);
  }
  else
  {
    _logger = iter->second;
  }
  return _logger;
}
void SLog::dump_trace()
{
  m_globalLog->info("dump_trace, m_trace.size() == {}", m_trace.size());
  for (auto iter = m_trace.begin(); iter != m_trace.end(); iter++)
  {
    m_globalLog->info("dump trace name:{}", iter->first);
    auto _logger = iter->second;
    _logger->dump_backtrace();
  }
}

void SLog::transto(std::string &x)
{
  for (std::size_t i = 0; i < x.length() - 1; i++)
  {
    if (x[i] == '%' && x[i + 1] != '%' && x[std::max((int)i - 1, 0)] != '\\')
    {
      x[i] = '{';
      x[i + 1] = '}';
    }
  }
}

void SLog::cleanup()
{
  spdlog::drop_all();
  m_loggers.clear();
}