suricata
log-stats.c
Go to the documentation of this file.
1 /* Copyright (C) 2014-2024 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  */
24 
25 #include "suricata-common.h"
26 #include "detect.h"
27 #include "pkt-var.h"
28 #include "conf.h"
29 
30 #include "threads.h"
31 #include "threadvars.h"
32 #include "tm-threads.h"
33 
34 #include "util-print.h"
35 
36 #include "util-debug.h"
37 
38 #include "output.h"
39 #include "log-stats.h"
40 #include "util-privs.h"
41 #include "util-buffer.h"
42 
43 #include "util-logopenfile.h"
44 
45 #define DEFAULT_LOG_FILENAME "stats.log"
46 #define MODULE_NAME "LogStatsLog"
47 #define OUTPUT_BUFFER_SIZE 16384
48 
49 #define LOG_STATS_TOTALS (1<<0)
50 #define LOG_STATS_THREADS (1<<1)
51 #define LOG_STATS_NULLS (1<<2)
52 
53 TmEcode LogStatsLogThreadInit(ThreadVars *, const void *, void **);
55 static void LogStatsLogDeInitCtx(OutputCtx *);
56 
57 typedef struct LogStatsFileCtx_ {
59  uint32_t flags; /** Store mode */
61 
62 typedef struct LogStatsLogThread_ {
66 
67 static int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st)
68 {
69  SCEnter();
70  LogStatsLogThread *aft = (LogStatsLogThread *)thread_data;
71 
72  struct timeval tval;
73  struct tm *tms;
74 
75  gettimeofday(&tval, NULL);
76  struct tm local_tm;
77  tms = SCLocalTime(tval.tv_sec, &local_tm);
78 
79  /* Calculate the Engine uptime */
80  double up_time_d = difftime(tval.tv_sec, st->start_time);
81  int up_time = (int)up_time_d; // ignoring risk of overflow here
82  int sec = up_time % 60; // Seconds in a minute
83  int in_min = up_time / 60;
84  int min = in_min % 60; // Minutes in a hour
85  int in_hours = in_min / 60;
86  int hours = in_hours % 24; // Hours in a day
87  int days = in_hours / 24;
88 
89  MemBufferWriteString(aft->buffer, "----------------------------------------------"
90  "-----------------------------------------------------\n");
91  MemBufferWriteString(aft->buffer, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
92  "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n",
93  tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour,
94  tms->tm_min, tms->tm_sec, days, hours, min, sec);
95  MemBufferWriteString(aft->buffer, "----------------------------------------------"
96  "-----------------------------------------------------\n");
97  MemBufferWriteString(aft->buffer, "%-60s | %-25s | %-s\n", "Counter", "TM Name", "Value");
98  MemBufferWriteString(aft->buffer, "----------------------------------------------"
99  "-----------------------------------------------------\n");
100 
101  /* global stats */
102  uint32_t u = 0;
103  if (aft->statslog_ctx->flags & LOG_STATS_TOTALS) {
104  for (u = 0; u < st->nstats; u++) {
105  if (st->stats[u].name == NULL)
106  continue;
107 
108  if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->stats[u].value == 0)
109  continue;
110 
111  char line[256];
112  size_t len = snprintf(line, sizeof(line), "%-60s | %-25s | %-" PRIu64 "\n",
113  st->stats[u].name, st->stats[u].tm_name, st->stats[u].value);
114 
115  /* since we can have many threads, the buffer might not be big enough.
116  * Expand if necessary. */
117  if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) {
119  }
120 
121  MemBufferWriteString(aft->buffer, "%s", line);
122  }
123  }
124 
125  /* per thread stats */
126  if (st->tstats != NULL && aft->statslog_ctx->flags & LOG_STATS_THREADS) {
127  /* for each thread (store) */
128  uint32_t x;
129  for (x = 0; x < st->ntstats; x++) {
130  uint32_t offset = x * st->nstats;
131 
132  /* for each counter */
133  for (u = offset; u < (offset + st->nstats); u++) {
134  if (st->tstats[u].name == NULL)
135  continue;
136 
137  if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->tstats[u].value == 0)
138  continue;
139 
140  char line[256];
141  size_t len = snprintf(line, sizeof(line), "%-45s | %-25s | %-" PRIi64 "\n",
142  st->tstats[u].name, st->tstats[u].tm_name, st->tstats[u].value);
143 
144  /* since we can have many threads, the buffer might not be big enough.
145  * Expand if necessary. */
146  if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) {
148  }
149 
150  MemBufferWriteString(aft->buffer, "%s", line);
151  }
152  }
153  }
154 
155  aft->statslog_ctx->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer),
157 
158  MemBufferReset(aft->buffer);
159 
160  SCReturnInt(0);
161 }
162 
163 TmEcode LogStatsLogThreadInit(ThreadVars *t, const void *initdata, void **data)
164 {
165  LogStatsLogThread *aft = SCCalloc(1, sizeof(LogStatsLogThread));
166  if (unlikely(aft == NULL))
167  return TM_ECODE_FAILED;
168 
169  if(initdata == NULL)
170  {
171  SCLogDebug("Error getting context for LogStats. \"initdata\" argument NULL");
172  SCFree(aft);
173  return TM_ECODE_FAILED;
174  }
175 
177  if (aft->buffer == NULL) {
178  SCFree(aft);
179  return TM_ECODE_FAILED;
180  }
181 
182  /* Use the Output Context (file pointer and mutex) */
183  aft->statslog_ctx= ((OutputCtx *)initdata)->data;
184 
185  *data = (void *)aft;
186  return TM_ECODE_OK;
187 }
188 
190 {
191  LogStatsLogThread *aft = (LogStatsLogThread *)data;
192  if (aft == NULL) {
193  return TM_ECODE_OK;
194  }
195 
196  MemBufferFree(aft->buffer);
197  /* clear memory */
198  memset(aft, 0, sizeof(LogStatsLogThread));
199 
200  SCFree(aft);
201  return TM_ECODE_OK;
202 }
203 
204 /** \brief Create a new http log LogFileCtx.
205  * \param conf Pointer to ConfNode containing this loggers configuration.
206  * \return NULL if failure, LogFileCtx* to the file_ctx if successful
207  * */
208 static OutputInitResult LogStatsLogInitCtx(SCConfNode *conf)
209 {
210  OutputInitResult result = { NULL, false };
211  LogFileCtx *file_ctx = LogFileNewCtx();
212  if (file_ctx == NULL) {
213  SCLogError("couldn't create new file_ctx");
214  return result;
215  }
216 
217  if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
218  LogFileFreeCtx(file_ctx);
219  return result;
220  }
221 
222  LogStatsFileCtx *statslog_ctx = SCCalloc(1, sizeof(LogStatsFileCtx));
223  if (unlikely(statslog_ctx == NULL)) {
224  LogFileFreeCtx(file_ctx);
225  return result;
226  }
227 
228  statslog_ctx->flags = LOG_STATS_TOTALS;
229 
230  if (conf != NULL) {
231  const char *totals = SCConfNodeLookupChildValue(conf, "totals");
232  const char *threads = SCConfNodeLookupChildValue(conf, "threads");
233  const char *nulls = SCConfNodeLookupChildValue(conf, "null-values");
234  SCLogDebug("totals %s threads %s", totals, threads);
235 
236  if ((totals != NULL && SCConfValIsFalse(totals)) &&
237  (threads != NULL && SCConfValIsFalse(threads))) {
238  LogFileFreeCtx(file_ctx);
239  SCFree(statslog_ctx);
240  SCLogError("Cannot disable both totals and threads in stats logging");
241  return result;
242  }
243 
244  if (totals != NULL && SCConfValIsFalse(totals)) {
245  statslog_ctx->flags &= ~LOG_STATS_TOTALS;
246  }
247  if (threads != NULL && SCConfValIsTrue(threads)) {
248  statslog_ctx->flags |= LOG_STATS_THREADS;
249  }
250  if (nulls != NULL && SCConfValIsTrue(nulls)) {
251  statslog_ctx->flags |= LOG_STATS_NULLS;
252  }
253  SCLogDebug("statslog_ctx->flags %08x", statslog_ctx->flags);
254  }
255 
256  statslog_ctx->file_ctx = file_ctx;
257 
258  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
259  if (unlikely(output_ctx == NULL)) {
260  LogFileFreeCtx(file_ctx);
261  SCFree(statslog_ctx);
262  return result;
263  }
264 
265  output_ctx->data = statslog_ctx;
266  output_ctx->DeInit = LogStatsLogDeInitCtx;
267 
268  SCLogDebug("STATS log output initialized");
269 
270  result.ctx = output_ctx;
271  result.ok = true;
272  return result;
273 }
274 
275 static void LogStatsLogDeInitCtx(OutputCtx *output_ctx)
276 {
277  LogStatsFileCtx *statslog_ctx = (LogStatsFileCtx *)output_ctx->data;
278  LogFileFreeCtx(statslog_ctx->file_ctx);
279  SCFree(statslog_ctx);
280  SCFree(output_ctx);
281 }
282 
284 {
285  OutputRegisterStatsModule(LOGGER_STATS, MODULE_NAME, "stats", LogStatsLogInitCtx,
287 }
log-stats.h
tm-threads.h
LogStatsFileCtx_::file_ctx
LogFileCtx * file_ctx
Definition: log-stats.c:58
StatsTable_::ntstats
uint32_t ntstats
Definition: output-stats.h:43
OUTPUT_BUFFER_SIZE
#define OUTPUT_BUFFER_SIZE
Definition: log-stats.c:47
len
uint8_t len
Definition: app-layer-dnp3.h:2
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:577
LogStatsLogThreadDeinit
TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *)
Definition: log-stats.c:189
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
LogFileNewCtx
LogFileCtx * LogFileNewCtx(void)
LogFileNewCtx() Get a new LogFileCtx.
Definition: util-logopenfile.c:795
MemBufferExpand
int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by)
expand membuffer by size of 'expand_by'
Definition: util-buffer.c:60
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:282
threads.h
LOG_STATS_NULLS
#define LOG_STATS_NULLS
Definition: log-stats.c:51
LogFileCtx_
Definition: util-logopenfile.h:85
LogStatsFileCtx_
Definition: log-stats.c:57
SCConfValIsFalse
int SCConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:602
util-privs.h
LogFileCtx_::Write
int(* Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp)
Definition: util-logopenfile.h:100
LogStatsLogThread_
Definition: log-stats.c:62
LOGGER_STATS
@ LOGGER_STATS
Definition: suricata-common.h:509
SCConfNodeLookupChildValue
const char * SCConfNodeLookupChildValue(const SCConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:877
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
LogStatsLogThread
struct LogStatsLogThread_ LogStatsLogThread
LogStatsLogThreadInit
TmEcode LogStatsLogThreadInit(ThreadVars *, const void *, void **)
Definition: log-stats.c:163
OutputCtx_::data
void * data
Definition: tm-modules.h:91
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
OutputCtx_
Definition: tm-modules.h:88
LogStatsLogThread_::buffer
MemBuffer * buffer
Definition: log-stats.c:64
util-debug.h
OutputRegisterStatsModule
void OutputRegisterStatsModule(LoggerId id, const char *name, const char *conf_name, OutputInitFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit)
Register a stats data output module.
Definition: output.c:575
OutputInitResult_::ctx
OutputCtx * ctx
Definition: output.h:47
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
StatsRecord_::name
const char * name
Definition: output-stats.h:32
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
pkt-var.h
OutputInitResult_::ok
bool ok
Definition: output.h:48
LogStatsFileCtx
struct LogStatsFileCtx_ LogStatsFileCtx
StatsTable_
Definition: output-stats.h:39
StatsRecord_::value
int64_t value
Definition: output-stats.h:35
SCLocalTime
struct tm * SCLocalTime(time_t timep, struct tm *result)
Definition: util-time.c:267
conf.h
TmEcode
TmEcode
Definition: tm-threads-common.h:80
StatsTable_::start_time
time_t start_time
Definition: output-stats.h:44
MemBuffer_
Definition: util-buffer.h:27
StatsTable_::stats
StatsRecord * stats
Definition: output-stats.h:40
LogStatsLogRegister
void LogStatsLogRegister(void)
Definition: log-stats.c:283
OutputInitResult_
Definition: output.h:46
DEFAULT_LOG_FILENAME
#define DEFAULT_LOG_FILENAME
Definition: log-stats.c:45
suricata-common.h
OutputCtx_::DeInit
void(* DeInit)(struct OutputCtx_ *)
Definition: tm-modules.h:94
LogStatsLogThread_::statslog_ctx
LogStatsFileCtx * statslog_ctx
Definition: log-stats.c:63
MODULE_NAME
#define MODULE_NAME
Definition: log-stats.c:46
MemBufferFree
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:86
StatsRecord_::tm_name
const char * tm_name
Definition: output-stats.h:34
LogFileFreeCtx
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
Definition: util-logopenfile.c:1012
StatsTable_::tstats
StatsRecord * tstats
Definition: output-stats.h:41
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:34
threadvars.h
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
SCConfLogOpenGeneric
int SCConfLogOpenGeneric(SCConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate)
open a generic output "log file", which may be a regular file or a socket
Definition: util-logopenfile.c:564
SCFree
#define SCFree(p)
Definition: util-mem.h:61
LogStatsFileCtx_::flags
uint32_t flags
Definition: log-stats.c:59
util-logopenfile.h
MEMBUFFER_SIZE
#define MEMBUFFER_SIZE(mem_buffer)
Get the MemBuffers current size.
Definition: util-buffer.h:61
util-buffer.h
LOG_STATS_TOTALS
#define LOG_STATS_TOTALS
Definition: log-stats.c:49
MemBufferWriteString
void MemBufferWriteString(MemBuffer *dst, const char *fmt,...)
Definition: util-buffer.c:130
LOG_STATS_THREADS
#define LOG_STATS_THREADS
Definition: log-stats.c:50
MEMBUFFER_BUFFER
#define MEMBUFFER_BUFFER(mem_buffer)
Get the MemBuffers underlying buffer.
Definition: util-buffer.h:51
MEMBUFFER_OFFSET
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
Definition: util-buffer.h:56
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
SCConfNode_
Definition: conf.h:37
StatsTable_::nstats
uint32_t nstats
Definition: output-stats.h:42
MemBufferCreateNew
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
output.h