【问题标题】:How to introduce date and time in log file如何在日志文件中引入日期和时间
【发布时间】:2011-09-14 04:37:39
【问题描述】:

我有一个用 C 编写的守护程序。我将事件记录在日志文件中,但现在我想在将事件写入日志文件时添加日期和时间。我怎样才能做到这一点?

当前日志文件:-

Event one occurred: result:
Event two occurred: result:

我希望日志文件看起来像:-

Sep 14 11:35:55 Event one occurred: result:
Sep 14 11:35:55 Event two occurred: result:

我的环境是 C 和 Linux。

【问题讨论】:

  • @Jonathan Leffler,我长期面临这些对齐问题,是否有任何参考页面可以参考和照顾自己?
  • 您是指问题中的布局?输入评论时,有一个帮助超链接;输入问题或答案时,在输入区域上方有一个橙色问号,可提供帮助。缩进4个空格将后面的内容视为代码;避免制表符。项目符号列表的行以星号或破折号开头(*-);您可以嵌套它们(子项目符号缩进 2 个或更多空格),并且您可以拥有与它们关联的代码(但对于第一级项目符号,以 8 个空格而不是 4 个空格为前缀)。编号列表有以1. 开头的行(点很重要)。等等。
  • 如果您的系统有syslog(3),最好使用它。

标签: c linux datetime logging


【解决方案1】:

您需要考虑使用dategmtimelocaltime 以获取实际日期和时间。

然后strftime可以为你格式化。

示例程序如下:

#include <stdio.h>
#include <time.h>

int main (void) {
    char buff[20];
    struct tm *sTm;

    time_t now = time (0);
    sTm = gmtime (&now);

    strftime (buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", sTm);
    printf ("%s %s\n", buff, "Event occurred now");

    return 0;
}

这个输出:

2011-09-14 04:52:11 Event occurred now

我更喜欢使用 UTC 而不是本地时间,因为它允许您将来自不同地理位置的机器的事件联系在一起,而不必担心时区差异。换句话说,请使用gmtime 而不是localtime,除非您非常确定不会跨越时区。

我也更喜欢 YYYY-MM-DD HH:MM:SS 格式,因为它比月份名称更容易排序,这对于提取和操作工具至关重要。


如果您有一个提供可选边界检查功能的实现(根据 C11 的附录 K),您可能可以优先使用 gmtime_s。它允许您指定 自己的 缓冲区来接收结果,因此在可重入和/或线程代码中更安全。

要使用它,您需要将代码更改为:

#include <stdio.h>
#define __STDC_WANT_LIB_EXT1__ 1
#include <time.h>

int main (void) {
    char buff[20];
    struct tm sTm;

    time_t now = time (0);
    gmtime_s (&now, &sTm);

    strftime (buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &sTm);
    printf ("%s %s\n", buff, "Event occurred now");

    return 0;
}

尽管您应该知道,Microsoft 的人员以某种方式设法以错误的方式获得了 gmtime_s 的论点。您需要考虑到这一点。

POSIX(和 Linux)还提供了一个 gmtime_r 函数,其执行方式与标准 gmtime_s 函数相同(参数按正确顺序)。

【讨论】:

  • 这些库的使用是否会导致可移植性问题?
  • 这些是纯 C89 函数——它们的可移植性是您可以合理期望的。可以肯定的是,您的守护程序还有许多其他部分不太便携。
  • @Thangaraj:不,它们都是在 ISO C 中定义的,尽可能地便携:-)
  • @Thangaraj:如果您使用的是 ISO C 编译器,那么就不存在可移植性问题。如果您不使用这样的编译器,那么它根本不应该被称为 C。 gccLinux 下(如您的标签所示)可以,但代码应在任何符合 ISO 标准的环境中编译和运行。
  • 收到错误:错误 C4996 'gmtime':此函数或变量可能不安全。考虑改用 gmtime_s。要禁用弃用,请使用 _CRT_SECURE_NO_WARNINGS。有关详细信息,请参阅在线帮助。
【解决方案2】:

根据@paxdiablo 的回答添加我的日志功能。使用本地时间,但可以通过修改 getFormattedTime() 来使用 gmt

common.h

// Returns the local date/time formatted as 2014-03-19 11:11:52
char* getFormattedTime(void);

// Remove path from filename
#define __SHORT_FILE__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

// Main log macro
#define __LOG__(format, loglevel, ...) printf("%s %-5s [%s] [%s:%d] " format "\n", getFormattedTime(), loglevel, __func__, __SHORT_FILE__, __LINE__, ## __VA_ARGS__)

// Specific log macros with 
#define LOGDEBUG(format, ...) __LOG__(format, "DEBUG", ## __VA_ARGS__)
#define LOGWARN(format, ...) __LOG__(format, "WARN", ## __VA_ARGS__)
#define LOGERROR(format, ...) __LOG__(format, "ERROR", ## __VA_ARGS__)
#define LOGINFO(format, ...) __LOG__(format, "INFO", ## __VA_ARGS__)

common.c

#include <time.h> // time_t, tm, time, localtime, strftime

// Returns the local date/time formatted as 2014-03-19 11:11:52
char* getFormattedTime(void) {

    time_t rawtime;
    struct tm* timeinfo;

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    // Must be static, otherwise won't work
    static char _retval[20];
    strftime(_retval, sizeof(_retval), "%Y-%m-%d %H:%M:%S", timeinfo);

    return _retval;
}

你可以像这样使用它们:

 LOGDEBUG("This is a log");
 LOGDEBUG("This is a log with params %d", 42);

产生输出:

2014-03-19 13:22:14 DEBUG [main] [main.c:54] This is a log
2014-03-19 13:22:14 DEBUG [main] [main.c:55] This is a log with params 42

【讨论】:

  • “本地时间”的实现是什么?
  • @PolinaC 这是一个ctime 函数,更多信息here
【解决方案3】:

例如,要获取当前时间,您可以使用time.h...

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

int main(void)
{
  time_t now;
  time(&now);

  printf("%s", ctime(&now)); // use ctime to format time to a string.

  return EXIT_SUCCESS;
}

您还可以按照 paxdiablo 的建议使用 strftime 以获得更多时间/日期格式的可能性。

当然,对于您的情况,ctime(&amp;now) 的结果将进入您的日志条目字符数组/字符串,而不是 printf

【讨论】:

  • 使用:time_t now = time(0); 可能会更好(尽管基本等效)。
  • @Jonathan Leffler - 确实是学术,但是是的,基本上是等价的。无论如何,paxdiablo 的答案现在比我的更完整,我只是发布这个来鼓励他添加代码示例。 ;)
【解决方案4】:

根据@inolasco 的回答,静态变量不是线程安全的。改为使用局部变量。

void getFormattedTime(char * const p, int sz) {
    time_t rawtime;
    struct tm* timeinfo;
    time(&rawtime);
    timeinfo = localtime(&rawtime);
    strftime(p, sz, "%Y-%m-%d %H:%M:%S", timeinfo);
}

int mylog(const char* fmt, ...) {
    // TODO: log to file also.
    // TODO: create a new log file daily
    va_list argptr;
    va_start(argptr, fmt);
    vfprintf(stderr, fmt, argptr);//log to stderr
    va_end(argptr);
}


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

#define  ___LOG___(fmt,level,path, ...) do{\
    /* using local var and using a long name to avoid conflict*/ \
    char LAgGV3nzJsTholGvGL2eTNXmhsqYe___xxooxxoo___[24];\
    getFormattedTime(LAgGV3nzJsTholGvGL2eTNXmhsqYe___xxooxxoo___,\
        sizeof(LAgGV3nzJsTholGvGL2eTNXmhsqYe___xxooxxoo___));\
    mylog("%s [%s] [%s:%d] [%s] " fmt "\n", \
        LAgGV3nzJsTholGvGL2eTNXmhsqYe___xxooxxoo___, \
        level,\
        path,\
        __LINE__, \
        __func__, \
        ## __VA_ARGS__);\
}while(0)

#define  trace(fmt, ...) ___LOG___(fmt, "TRACE",__SHORT_FILE__, ## __VA_ARGS__)
#define  debug(fmt, ...) ___LOG___(fmt, "DEBUG",__SHORT_FILE__, ## __VA_ARGS__)
#define   info(fmt, ...) ___LOG___(fmt,  "INFO",__SHORT_FILE__, ## __VA_ARGS__)
#define   warn(fmt, ...) ___LOG___(fmt,  "WARN",__SHORT_FILE__, ## __VA_ARGS__)
#define  error(fmt, ...) ___LOG___(fmt, "ERROR",__SHORT_FILE__, ## __VA_ARGS__)
#define tracel(fmt, ...) ___LOG___(fmt, "TRACE",      __FILE__, ## __VA_ARGS__)
#define debugl(fmt, ...) ___LOG___(fmt, "DEBUG",      __FILE__, ## __VA_ARGS__)
#define  infol(fmt, ...) ___LOG___(fmt,  "INFO",      __FILE__, ## __VA_ARGS__)
#define  warnl(fmt, ...) ___LOG___(fmt,  "WARN",      __FILE__, ## __VA_ARGS__)
#define errorl(fmt, ...) ___LOG___(fmt, "ERROR",      __FILE__, ## __VA_ARGS__)

这样称呼他们:

info("%s", "a log");
infol("%s", "a log");

生产:

2017-09-06 15:55:42 [INFO] [main.c:25] [main] a log
2017-09-06 15:58:08 [INFO] [d:\main.c:25] [main] a log

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 2019-09-05
    相关资源
    最近更新 更多