2 * copyright (c) 2007-2011 Emil Mikulic.
4 * daylog.c: daily usage log
6 * You may use, modify and redistribute this file under the terms of the
7 * GNU General Public License version 2. (see COPYING.GPL)
10 #define _GNU_SOURCE 1 /* for O_NOFOLLOW on Linux */
25 static const char *daylog_fn
= NULL
;
26 static long today_real
, tomorrow_real
;
27 static uint64_t bytes_in
, bytes_out
, pkts_in
, pkts_out
;
29 #define DAYLOG_DATE_LEN 26 /* strlen("1900-01-01 00:00:00 +1234") + 1 */
30 static char datebuf
[DAYLOG_DATE_LEN
];
32 static char *fmt_date(time_t when
) {
35 "%Y-%m-%d %H:%M:%S %z",
36 localtime(&when
)) == 0)
37 errx(1, "strftime() failed in fmt_date()");
41 /* Given some time today, find the first second of tomorrow. */
42 static time_t tomorrow(time_t t_before
) {
46 lt
= localtime(&t_before
);
47 memcpy(&tm
, lt
, sizeof(tm
));
51 tm
.tm_mday
= lt
->tm_mday
+ 1; /* tomorrow */
52 t_after
= mktime(&tm
);
53 assert(t_after
> t_before
);
58 static void daylog_write(const char *format
, ...) {
64 assert(daylog_fn
!= NULL
);
65 fd
= open(daylog_fn
, O_WRONLY
| O_APPEND
| O_CREAT
| O_NOFOLLOW
, 0600);
67 warn("daylog_write: couldn't open '%s' for append", daylog_fn
);
73 str_vappendf(buf
, format
, va
);
76 wr
= str_write(buf
, fd
);
78 warn("daylog_write: couldn't write to '%s'", daylog_fn
);
79 else if (wr
!= (ssize_t
)str_len(buf
))
80 warnx("daylog_write: truncated write to '%s': wrote %d of %d bytes",
88 static void daylog_emit(void) {
89 daylog_write("%s|%qu|%qu|%qu|%qu|%qu\n",
90 fmt_date(today_real
), (uint64_t)today_real
,
91 bytes_in
, bytes_out
, pkts_in
, pkts_out
);
94 void daylog_init(const char *filename
) {
96 today_real
= now_real();
97 tomorrow_real
= tomorrow(today_real
);
98 verbosef("today is %ld, tomorrow is %ld",
99 (long)today_real
, (long)tomorrow_real
);
100 bytes_in
= bytes_out
= pkts_in
= pkts_out
= 0;
102 daylog_write("# logging started at %s (%qu)\n",
103 fmt_date(today_real
), (uint64_t)today_real
);
106 void daylog_free(void) {
107 today_real
= now_real();
108 daylog_emit(); /* Emit what's currently accumulated before we exit. */
109 daylog_write("# logging stopped at %s (%qu)\n",
110 fmt_date(today_real
), (uint64_t)today_real
);
113 void daylog_acct(uint64_t amount
, enum graph_dir dir
) {
114 if (daylog_fn
== NULL
)
115 return; /* daylogging disabled */
117 /* Check if we need to update the log. */
118 if (now_real() >= tomorrow_real
) {
121 today_real
= now_real();
122 tomorrow_real
= tomorrow(today_real
);
123 bytes_in
= bytes_out
= pkts_in
= pkts_out
= 0;
124 verbosef("updated daylog, tomorrow = %ld", (long)tomorrow_real
);
128 if (dir
== GRAPH_IN
) {
132 assert(dir
== GRAPH_OUT
);
138 /* vim:set ts=3 sw=3 tw=78 et: */