demo.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int add(void)
{
return 20;
}
void test01()
{
// int res = add(12, 23, 12);
// printf("%d", res);
}
int main()
{
setbuf(stdout, NULL);
test01();
return 0;
}
logger.cpp
#include "logger.h"
#include <cstring>
#include <cstdarg>
#include <ctime>
#include <algorithm>
#include <sys/stat.h>
#include <io.h>
using namespace std;
ofstream Logger::s_ofs;
string Logger::s_projectName("zhifubao");
string Logger::s_logDirPath;
string Logger::s_logDirName("output");
void Logger::WriteLogger(const char *filename, const char *funcname, int line, const char *level, const char *fmt, ...)
{
// 获取当前的日志文件夹路径
string currentFilePath = __FILE__;
size_t pos = currentFilePath.find_last_of("/\\");
s_logDirPath = currentFilePath.substr(0, pos) + "/" + s_logDirName;
if (!s_ofs.is_open()) {
struct stat dirInfo;
string logFileName;
// 判断日志文件夹是否存在,如果不存在,则创建一个文件夹
if (stat(s_logDirPath.c_str(), &dirInfo) != 0) { // 不存在,则创建一个新的日志文件夹
mkdir(s_logDirPath.c_str());
logFileName = GenLogFileName();
} else {
// 如果存在
const vector<std::string> &files = GetLogFiles();
if (files.empty()) { // 如果为空,则创建一个新的
logFileName = GenLogFileName();
} else { // 如果不为空,则找到最近的那个日志文件
logFileName = files.back();
}
}
s_ofs.open(s_logDirPath + "/" + logFileName, ios::app);
}
// 解析不定义参数
va_list vaList;
va_start(vaList, fmt);
char logMsg[LOG_MSG_MAX_LEN] = {0};
// int vsprintf (char *__stream, const char *__format, __builtin_va_list __local_argv)
vsprintf(logMsg, fmt, vaList);
va_end(vaList);
// (1)构造一条完整的日志
// 2023-10-19 10:06:32 [login.c] [LoginCheck:50] [INFO] user admin login success
char *p = strrchr(filename, '/');
if (p == nullptr) {
p = strrchr(filename, '\\');
}
// (2)获取当前的时间
string currentTime = GetCurrentTime("%Y-%m-%d %H:%M:%S");
char fullMsg[LOG_FULL_MSG_MAX_LEN] = {0};
sprintf(fullMsg, "%s [%s] [%s:%d] [%s] %s", currentTime.c_str(), p + 1, funcname, line, level, logMsg);
// 判断文件大小,如果超过最大大小,则把上个文件关闭,重新打开文件
if (s_ofs.tellp() >= LOG_FILE_MAX_SIZE) {
s_ofs.close();
// 打开新的文件之前,要判断文件的个数,如果最大个数,则删除最远的那个日志文件
const vector<std::string> &files = GetLogFiles();
if (files.size() >= LOG_FILE_MAX_NUM) {
string delFilePath = s_logDirPath + "/" + files.front();
remove(delFilePath.c_str());
}
string newFileName = GenLogFileName();
s_ofs.open(s_logDirPath + "/" + newFileName, ios::app);
}
// (3)写入文件中
s_ofs << fullMsg << endl;
s_ofs.flush(); // 刷新缓冲区,立即会写入文件
}
string Logger::GetCurrentTime(const std::string &fmt)
{
time_t tt = time(nullptr);
// struct tm * localtime(const time_t *_Time)
struct tm *tmPtr = localtime(&tt);
// size_t strftime(char *_Buf,size_t _SizeInBytes,const char *_Format,const struct tm *_Tm);
char buffer[LOG_TIME_BUFFER_LEN] = {0};
strftime(buffer, sizeof(buffer), fmt.c_str(), tmPtr);
return buffer;
}
std::string Logger::GenLogFileName()
{
// 项目名称_YYMMDD_HHMMSS.log
string currentTime = GetCurrentTime("%Y%m%d_%H%M%S");
string filename = s_projectName + "_" + currentTime + ".log";
return filename;
}
std::vector<std::string> Logger::GetLogFiles()
{
vector<string> files;
// 如何查找某个文件夹下的日志文件
intptr_t fileHandle;
struct _finddata_t fileInfo;
string dirPath = s_logDirPath + "/*.log";
if ((fileHandle = _findfirst(dirPath.c_str(), &fileInfo)) != -1) {
do {
files.emplace_back(fileInfo.name);
} while (_findnext(fileHandle, &fileInfo) == 0);
_findclose(fileHandle);
}
sort(files.begin(), files.end());
return files;
}
logger.h
#ifndef CPP0717_LOGGER_H
#define CPP0717_LOGGER_H
#include <string>
#include <fstream>
#include <vector>
#define LOGGER_INFO(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "INFO", fmt, ##__VA_ARGS__)
#define LOGGER_ERROR(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "ERROR", fmt, ##__VA_ARGS__)
#define LOGGER_WARNING(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "WARNING", fmt, ##__VA_ARGS__)
#define LOGGER_FATAL(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "FATAL", fmt, ##__VA_ARGS__)
#define LOGGER_DEBUG(fmt, ...) Logger::WriteLogger(__FILE__, __FUNCTION__, __LINE__, "DEBUG", fmt, ##__VA_ARGS__)
class Logger {
public:
static void
WriteLogger(const char *filename, const char *funcname, int line, const char *level, const char *fmt, ...);
private:
// 获取当前的时间
static std::string GetCurrentTime(const std::string &fmt);
// 获取日志输出文件夹下的文件
static std::vector<std::string> GetLogFiles();
// 生成新的日志文件名称
static std::string GenLogFileName();
// 字节换算单位
static const int BYTE_UNIT = 1024;
// 最大的日志文件个数
static const int LOG_FILE_MAX_NUM = 10;
// 日志文件最大大小
static const int LOG_FILE_MAX_SIZE = 10 * BYTE_UNIT * BYTE_UNIT;
// 日志可变长参数的长度
static const int LOG_MSG_MAX_LEN = 512;
// 一条完整的日志最大长度
static const int LOG_FULL_MSG_MAX_LEN = 1024;
// 日志中时间字符串的长度
static const int LOG_TIME_BUFFER_LEN = 32;
// 日志写入文件流
static std::ofstream s_ofs;
// 项目名称
static std::string s_projectName;
// 日志输出的文件夹路径
static std::string s_logDirPath;
// 日志输出的文件夹名称
static std::string s_logDirName;
};
#endif //CPP0717_LOGGER_H
logger_test.cpp
#include <iostream>
#include <string>
#include <vector>
#include <cstdarg>
#include <io.h>
#include "logger.h"
using namespace std;
/*
函数的不定长参数:
...
如何在不定长参数的函数中获取参数的值
(1)按照地址偏移方式[本质]
(2)借助头文件中的
#include <stdarg.h>
#include <cstdarg>
编码规范:
函数的参数个数一般不超过5个
为什么:
栈:函数的返回值,函数的形参,局部变量
实际中,函数的形参如果比较少的时候,一般是放在寄存器中,
由于寄存器的访问速度比栈访问速度快。所以建议函数的形参个数不宜太多
*/
int add(int a, int b, int c, ...)
{
int *p1 = &a;
cout << p1 << endl;
int *p2 = &b;
cout << p2 << endl;
int *p3 = &c;
cout << p3 << endl;
cout << *(p3 + 2) << endl;
cout << *(p3 + 4) << endl;
return a + b;
}
int sum(int n, ...)
{
int *p = &n;
int total = 0;
for (int i = 0; i < n; ++i) {
total += *(p + 2 * (i + 1)); // 2 4 6 8 10
}
return total;
}
void test01()
{
int res = add(1, 2, 3, 4, 5);
cout << res << endl;
int arr[] = {1, 2, 3, 4, 5};
int *p = arr;
/*
指针+n,实际偏移的字节数为指针所指向的内存块类型占用的字节数 * n,
即sizeof(类型) * n个字节
*/
p + 1;
}
void test02()
{
int res = sum(5, 1, 2, 3, 4, 5);
cout << res << endl;
res = sum(3, 1, 2, 3);
cout << res << endl;
}
int sum2(int n, ...)
{
va_list vaList;
va_start(vaList, n); // 将变量n的下一个地址赋值给vaList
int total = 0;
for (int i = 0; i < n; ++i) {
total += va_arg(vaList, int);
}
va_end(vaList); // 将vaList置为空指针
return total;
}
void test03()
{
int res = sum2(5, 1, 2, 3, 4, 5);
cout << res << endl;
// res = sum2(3, 1, 2, 3);
// cout << res << endl;
}
// 使用stdarg获取不同类型的变量值
void func(int arg, ...)
{
va_list vaList;
va_start(vaList, arg);
int a = va_arg(vaList, int);
cout << a << endl;
char b = va_arg(vaList, int);
cout << b << endl;
float c = va_arg(vaList, double);
cout << c << endl;
double d = va_arg(vaList, double);
cout << d << endl;
char *e = va_arg(vaList, char *);
cout << e << endl;
va_end(vaList);
}
void test04()
{
int a = 10;
char b = '*';
float c = 3.14f;
double d = 3.14;
char e[] = "hello";
func(5, a, b, c, d, e);
}
// int printf(const char *__format, ...)
// int vprintf(const char *__format, __builtin_va_list __local_argv)
// typedef __builtin_va_list __gnuc_va_list;
// typedef __gnuc_va_list va_list;
void info(const char *fmt, ...)
{
va_list p;
va_start(p, fmt);
vprintf(fmt, p);
va_end(p);
}
void test05()
{
info("%d %d\n", 10, 20);
info("%s %d %.2f\n", "china", 20, 3.1415926);
}
void test_log()
{
LOGGER_INFO("start...");
for (int i = 0; i < 2000000; ++i) {
LOGGER_INFO("maping: %d", i);
}
LOGGER_INFO("end...");
LOGGER_INFO("data: %s %d %.2f", "zhaosi", 10, 3.1415926);
LOGGER_ERROR("file[%s] is not found", "zhaosi.txt");
}
/*
限制文件的个数:
10个文件
当前已经写了9个满的,1个正在写入
当你要重新产生一个新的日志文件时,首先得统计一下当前一共有几个日志文件
如果当前的文件个数>=10, 应该把最远的那个文件给删除吧
*/
int main()
{
setbuf(stdout, nullptr);
// test01();
// test02();
// test03();
// test04();
// test05();
test_log();
return 0;
}
readme.md
日志:
为了记录程序运行时的一些关键的逻辑、警告、错误信息的。方便日后的问题定位
日志的级别:
DEBUG: 调试日志
INFO: 详细的常规日志
WARNING: 警告日志
ERROR: 常规错误日志
FATAL: 致命错误日志
日志文件格式:
文件格式一般都是以.log结尾
日志信息格式:
日期 时间 模块 文件名 函数名 行号 级别 具体的信息
2023-10-19 10:06:32 [login] [login.c] [LoginCheck:50] [INFO] user admin login success
2023-10-19 10:06:32 [module:login] [filename:login.c] [funcname:LoginCheck] [line:50] [INFO] user admin login success
规则:
(1)日志内容中不能出现敏感信息【手机号、密码、工号、邮箱、token、session、证书】
(2)日志内容中不能有绝对路径
(3)日志单个文件大小需要进行限制。10M/50M
(4)日志需要具备转储功能,同时日志文件的个数也需要限制(7个/10个)。
注意:
日志的打印功能需要考虑线程安全问题
```
&spm=1001.2101.3001.5002&articleId=133997655&d=1&t=3&u=f0960447d3d0482d95553b37c8d3f5ce)
273

被折叠的 条评论
为什么被折叠?



