spdlog

基本功能:对应不同等级的调试、日志信息进行打印:

链接:https://blog.csdn.net/new9232/article/details/136220649
链接:https://blog.csdn.net/alwaysrun/article/details/122771208

cmakelist.txt

1
2
3
4
5
6
7
8
9
10
11
12

cmake_minimum_required(VERSION 3.0.0)
project(use_spdlog VERSION 0.1.0 LANGUAGES C CXX)

include(CTest)
enable_testing()

add_executable(use_spdlog main.cpp)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
//这里如果不放在#include "spdlog/spdlog.h"之前,那么会和spdlog.h中# include common.h中的
//#if !defined(SPDLOG_ACTIVE_LEVEL)
// #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
//#endif
//默认定义冲突,导致重定义

#include <iostream>
#include "spdlog/spdlog.h"
#include <spdlog/sinks/basic_file_sink.h>


int main(int, char**){



std::shared_ptr<spdlog::logger> mylogger = spdlog::basic_logger_mt("spdlog1", "spdlog1.log");
// 设置日志格式. 参数含义: [日志标识符] [日期] [日志级别] [线程号] [文件名 函数名:行号] [数据]
mylogger->set_pattern("[%n] [%Y-%m-%d %H:%M:%S.%e] [%l] [%t] [%s %!:%#] %v");

mylogger->set_level(spdlog::level::trace);
spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志缓冲区

SPDLOG_LOGGER_TRACE(mylogger, "Welcome to info spdlog. {}", "hello!");
SPDLOG_LOGGER_DEBUG(mylogger, "Welcome to info spdlog. {}", "hello!");
SPDLOG_LOGGER_INFO(mylogger, "Welcome to info spdlog. {}", "hello!");
SPDLOG_LOGGER_ERROR(mylogger, "Welcome to info spdlog. {}", "hello!");

// 结束程序前刷新日志
mylogger->flush();



}


打印trace及以上等级的日志信息,利用SPDLOG_LOGGER_INFO(mylogger, “Welcome to info spdlog. {}”, “hello!”);方法可以打印所在位置、行数。除了设置mylogger->set_level(spdlog::level::trace);还要设置一个宏(第一个宏)。

下面这种方法就不需要额外设置宏,直接用my_logger接口函数打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35



#include <iostream>
#include "spdlog/spdlog.h"
#include <spdlog/sinks/basic_file_sink.h>


int main(int, char**){



std::shared_ptr<spdlog::logger> mylogger = spdlog::basic_logger_mt("spdlog1", "spdlog1.log");
// 设置日志格式. 参数含义: [日志标识符] [日期] [日志级别] [线程号] [文件名 函数名:行号] [数据]
mylogger->set_pattern("[%n] [%Y-%m-%d %H:%M:%S.%e] [%l] [%t] [%s %!:%#] %v");

mylogger->set_level(spdlog::level::trace);
spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志缓冲区

mylogger->trace("Welcome to info spdlog!");
mylogger->debug("Welcome to info spdlog!");
mylogger->info("Welcome to info spdlog!");
mylogger->warn("Welcome to info spdlog!");
mylogger->error("Welcome to info spdlog!");
mylogger->critical("Welcome to info spdlog!");

// 刷新
mylogger->flush_on(spdlog::level::debug);

// 结束程序前刷新日志
mylogger->flush();

}


一种使用mylogger接口来打印所在文件和行数的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <string.h>
#include <iostream>

#ifdef WIN32
#define __FILENAME__ (strrchr(__FILE__, '\\') ? (strrchr(__FILE__, '\\') + 1):__FILE__)
#else
#define __FILENAME__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1):__FILE__)
#endif

int main()
{
try
{
// 基本文件
std::shared_ptr<spdlog::logger> my_logger = spdlog::basic_logger_mt("spdlog", "spdlog.txt");
// 设置日志格式. 参数含义: [日志标识符] [日期] [日志级别] [线程号] [数据]
my_logger->set_pattern("[%n][%Y-%m-%d %H:%M:%S.%e] [%l] [%t] %v");
my_logger->set_level(spdlog::level::debug);
spdlog::flush_every(std::chrono::seconds(5)); // 定期刷新日志缓冲区

my_logger->trace("Welcome to info spdlog!");
my_logger->debug("[{0}:{1}] Welcome to info spdlog!", __FILENAME__, __LINE__);
my_logger->info("[{0}:{1}] Welcome to info spdlog!", __FILENAME__, __LINE__);
my_logger->error("Welcome to info spdlog!");

my_logger->flush();

system("pause");
}
catch (const spdlog::spdlog_ex& ex)
{
std::cout << "Log initialization failed: " << ex.what() << std::endl;
}
}


common.h

#define SPDLOGDEPRECATED _attribute((deprecated))

  下面代码作用是利用SPDLOG_DEPRECATED管理库中的函数、变量,被标记的函数变量被客户调用时会报warning,该函数、变量即将被下个版本更新掉,请谨慎使用。

链接:https://blog.csdn.net/benkaoya/article/details/52368638

1
2
3
4
5
6
7
8
9
10

#if defined(__GNUC__) || defined(__clang__)
#define SPDLOG_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define SPDLOG_DEPRECATED __declspec(deprecated)
#else
#define SPDLOG_DEPRECATED
#endif


使用例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

#include <stdio.h>
#include <stdlib.h>

#ifdef __GNUC__
# define GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#else
# define GCC_VERSION_AT_LEAST(x,y) 0
#endif

#if GCC_VERSION_AT_LEAST(3,1)
# define attribute_deprecated __attribute__((deprecated))
#elif defined(_MSC_VER)
# define attribute_deprecated __declspec(deprecated)
#else
# define attribute_deprecated
#endif


/* Variable Attribute */
attribute_deprecated int variable_old = 0;

/* Function Attribute */
attribute_deprecated void function_old(void);

void function_old(void)
{
printf("old function.\n");
return;
}

int main(void)
{
variable_old++;

function_old();

return EXIT_SUCCESS;
}


warning如下:

1
2
3
4
5
6
7

# gcc attribute_deprecated.c -o test
attribute_deprecated.c: In function ‘main’:
attribute_deprecated.c:33: warning: ‘variable_old’ is deprecated (declared at attribute_deprecated.c:20)
attribute_deprecated.c:35: warning: ‘function_old’ is deprecated (declared at attribute_deprecated.c:25)


空的宏定义

1
2
3
4
5
6
7
8

#ifdef SPDLOG_COMPILED_LIB
#else // !defined(SPDLOG_COMPILED_LIB)
#define SPDLOG_API
#define SPDLOG_HEADER_ONLY
#define SPDLOG_INLINE inline
#endif // #ifdef SPDLOG_COMPILED_LIB

可以看到上面代码中宏定义被定义为空。虽然定义为空,但是定义了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#pragma once

#include <spdlog/details/log_msg.h>
#include <spdlog/formatter.h>

namespace spdlog {

namespace sinks {
class SPDLOG_API sink {
public:
virtual ~sink() = default;
virtual void log(const details::log_msg &msg) = 0;
virtual void flush() = 0;
virtual void set_pattern(const std::string &pattern) = 0;
virtual void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) = 0;

void set_level(level::level_enum log_level);
level::level_enum level() const;
bool should_log(level::level_enum msg_level) const;

protected:
// sink log level - default is all
level_t level_{level::trace};
};

} // namespace sinks
} // namespace spdlog

#ifdef SPDLOG_HEADER_ONLY
#include "sink-inl.h"
#endif


因此class SPDLOG_API sink 实际为class sink,在sink.h结尾处也会把sink-inl.h给包括进来。