suricata
log-stats.c
Go to the documentation of this file.
1 /* Copyright (C) 2014 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 #include "util-unittest.h"
36 
37 #include "util-debug.h"
38 
39 #include "output.h"
40 #include "log-stats.h"
41 #include "util-privs.h"
42 #include "util-buffer.h"
43 
44 #include "util-logopenfile.h"
45 #include "util-time.h"
46 
47 #define DEFAULT_LOG_FILENAME "stats.log"
48 #define MODULE_NAME "LogStatsLog"
49 #define OUTPUT_BUFFER_SIZE 16384
50 
51 #define LOG_STATS_TOTALS (1<<0)
52 #define LOG_STATS_THREADS (1<<1)
53 #define LOG_STATS_NULLS (1<<2)
54 
55 TmEcode LogStatsLogThreadInit(ThreadVars *, const void *, void **);
57 static void LogStatsLogDeInitCtx(OutputCtx *);
58 
59 typedef struct LogStatsFileCtx_ {
61  uint32_t flags; /** Store mode */
63 
64 typedef struct LogStatsLogThread_ {
68 
69 static int LogStatsLogger(ThreadVars *tv, void *thread_data, const StatsTable *st)
70 {
71  SCEnter();
72  LogStatsLogThread *aft = (LogStatsLogThread *)thread_data;
73 
74  struct timeval tval;
75  struct tm *tms;
76 
77  gettimeofday(&tval, NULL);
78  struct tm local_tm;
79  tms = SCLocalTime(tval.tv_sec, &local_tm);
80 
81  /* Calculate the Engine uptime */
82  double up_time_d = difftime(tval.tv_sec, st->start_time);
83  int up_time = (int)up_time_d; // ignoring risk of overflow here
84  int sec = up_time % 60; // Seconds in a minute
85  int in_min = up_time / 60;
86  int min = in_min % 60; // Minutes in a hour
87  int in_hours = in_min / 60;
88  int hours = in_hours % 24; // Hours in a day
89  int days = in_hours / 24;
90 
91  MemBufferWriteString(aft->buffer, "----------------------------------------------"
92  "--------------------------------------\n");
93  MemBufferWriteString(aft->buffer, "Date: %" PRId32 "/%" PRId32 "/%04d -- "
94  "%02d:%02d:%02d (uptime: %"PRId32"d, %02dh %02dm %02ds)\n",
95  tms->tm_mon + 1, tms->tm_mday, tms->tm_year + 1900, tms->tm_hour,
96  tms->tm_min, tms->tm_sec, days, hours, min, sec);
97  MemBufferWriteString(aft->buffer, "----------------------------------------------"
98  "--------------------------------------\n");
99  MemBufferWriteString(aft->buffer, "%-45s | %-25s | %-s\n", "Counter", "TM Name",
100  "Value");
101  MemBufferWriteString(aft->buffer, "----------------------------------------------"
102  "--------------------------------------\n");
103 
104  /* global stats */
105  uint32_t u = 0;
106  if (aft->statslog_ctx->flags & LOG_STATS_TOTALS) {
107  for (u = 0; u < st->nstats; u++) {
108  if (st->stats[u].name == NULL)
109  continue;
110 
111  if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->stats[u].value == 0)
112  continue;
113 
114  char line[256];
115  size_t len = snprintf(line, sizeof(line), "%-45s | %-25s | %-" PRIu64 "\n",
116  st->stats[u].name, st->stats[u].tm_name, st->stats[u].value);
117 
118  /* since we can have many threads, the buffer might not be big enough.
119  * Expand if necessary. */
120  if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) {
122  }
123 
124  MemBufferWriteString(aft->buffer, "%s", line);
125  }
126  }
127 
128  /* per thread stats */
129  if (st->tstats != NULL && aft->statslog_ctx->flags & LOG_STATS_THREADS) {
130  /* for each thread (store) */
131  uint32_t x;
132  for (x = 0; x < st->ntstats; x++) {
133  uint32_t offset = x * st->nstats;
134 
135  /* for each counter */
136  for (u = offset; u < (offset + st->nstats); u++) {
137  if (st->tstats[u].name == NULL)
138  continue;
139 
140  if (!(aft->statslog_ctx->flags & LOG_STATS_NULLS) && st->tstats[u].value == 0)
141  continue;
142 
143  char line[256];
144  size_t len = snprintf(line, sizeof(line), "%-45s | %-25s | %-" PRIi64 "\n",
145  st->tstats[u].name, st->tstats[u].tm_name, st->tstats[u].value);
146 
147  /* since we can have many threads, the buffer might not be big enough.
148  * Expand if necessary. */
149  if (MEMBUFFER_OFFSET(aft->buffer) + len >= MEMBUFFER_SIZE(aft->buffer)) {
151  }
152 
153  MemBufferWriteString(aft->buffer, "%s", line);
154  }
155  }
156  }
157 
158  aft->statslog_ctx->file_ctx->Write((const char *)MEMBUFFER_BUFFER(aft->buffer),
160 
161  MemBufferReset(aft->buffer);
162 
163  SCReturnInt(0);
164 }
165 
166 TmEcode LogStatsLogThreadInit(ThreadVars *t, const void *initdata, void **data)
167 {
169  if (unlikely(aft == NULL))
170  return TM_ECODE_FAILED;
171  memset(aft, 0, sizeof(LogStatsLogThread));
172 
173  if(initdata == NULL)
174  {
175  SCLogDebug("Error getting context for LogStats. \"initdata\" argument NULL");
176  SCFree(aft);
177  return TM_ECODE_FAILED;
178  }
179 
181  if (aft->buffer == NULL) {
182  SCFree(aft);
183  return TM_ECODE_FAILED;
184  }
185 
186  /* Use the Output Context (file pointer and mutex) */
187  aft->statslog_ctx= ((OutputCtx *)initdata)->data;
188 
189  *data = (void *)aft;
190  return TM_ECODE_OK;
191 }
192 
194 {
195  LogStatsLogThread *aft = (LogStatsLogThread *)data;
196  if (aft == NULL) {
197  return TM_ECODE_OK;
198  }
199 
200  MemBufferFree(aft->buffer);
201  /* clear memory */
202  memset(aft, 0, sizeof(LogStatsLogThread));
203 
204  SCFree(aft);
205  return TM_ECODE_OK;
206 }
207 
208 /** \brief Create a new http log LogFileCtx.
209  * \param conf Pointer to ConfNode containing this loggers configuration.
210  * \return NULL if failure, LogFileCtx* to the file_ctx if succesful
211  * */
212 static OutputInitResult LogStatsLogInitCtx(ConfNode *conf)
213 {
214  OutputInitResult result = { NULL, false };
215  LogFileCtx *file_ctx = LogFileNewCtx();
216  if (file_ctx == NULL) {
217  SCLogError("couldn't create new file_ctx");
218  return result;
219  }
220 
221  if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
222  LogFileFreeCtx(file_ctx);
223  return result;
224  }
225 
226  LogStatsFileCtx *statslog_ctx = SCMalloc(sizeof(LogStatsFileCtx));
227  if (unlikely(statslog_ctx == NULL)) {
228  LogFileFreeCtx(file_ctx);
229  return result;
230  }
231  memset(statslog_ctx, 0x00, sizeof(LogStatsFileCtx));
232 
233  statslog_ctx->flags = LOG_STATS_TOTALS;
234 
235  if (conf != NULL) {
236  const char *totals = ConfNodeLookupChildValue(conf, "totals");
237  const char *threads = ConfNodeLookupChildValue(conf, "threads");
238  const char *nulls = ConfNodeLookupChildValue(conf, "null-values");
239  SCLogDebug("totals %s threads %s", totals, threads);
240 
241  if ((totals != NULL && ConfValIsFalse(totals)) &&
242  (threads != NULL && ConfValIsFalse(threads))) {
243  LogFileFreeCtx(file_ctx);
244  SCFree(statslog_ctx);
245  SCLogError("Cannot disable both totals and threads in stats logging");
246  return result;
247  }
248 
249  if (totals != NULL && ConfValIsFalse(totals)) {
250  statslog_ctx->flags &= ~LOG_STATS_TOTALS;
251  }
252  if (threads != NULL && ConfValIsTrue(threads)) {
253  statslog_ctx->flags |= LOG_STATS_THREADS;
254  }
255  if (nulls != NULL && ConfValIsTrue(nulls)) {
256  statslog_ctx->flags |= LOG_STATS_NULLS;
257  }
258  SCLogDebug("statslog_ctx->flags %08x", statslog_ctx->flags);
259  }
260 
261  statslog_ctx->file_ctx = file_ctx;
262 
263  OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
264  if (unlikely(output_ctx == NULL)) {
265  LogFileFreeCtx(file_ctx);
266  SCFree(statslog_ctx);
267  return result;
268  }
269 
270  output_ctx->data = statslog_ctx;
271  output_ctx->DeInit = LogStatsLogDeInitCtx;
272 
273  SCLogDebug("STATS log output initialized");
274 
275  result.ctx = output_ctx;
276  result.ok = true;
277  return result;
278 }
279 
280 static void LogStatsLogDeInitCtx(OutputCtx *output_ctx)
281 {
282  LogStatsFileCtx *statslog_ctx = (LogStatsFileCtx *)output_ctx->data;
283  LogFileFreeCtx(statslog_ctx->file_ctx);
284  SCFree(statslog_ctx);
285  SCFree(output_ctx);
286 }
287 
289 {
291  LogStatsLogInitCtx, LogStatsLogger, LogStatsLogThreadInit,
293 }
log-stats.h
tm-threads.h
LogStatsFileCtx_::file_ctx
LogFileCtx * file_ctx
Definition: log-stats.c:60
StatsTable_::ntstats
uint32_t ntstats
Definition: output-stats.h:43
OUTPUT_BUFFER_SIZE
#define OUTPUT_BUFFER_SIZE
Definition: log-stats.c:49
len
uint8_t len
Definition: app-layer-dnp3.h:2
LogStatsLogThreadDeinit
TmEcode LogStatsLogThreadDeinit(ThreadVars *, void *)
Definition: log-stats.c:193
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:660
MemBufferExpand
int MemBufferExpand(MemBuffer **buffer, uint32_t expand_by)
expand membuffer by size of 'expand_by'
Definition: util-buffer.c:64
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
threads.h
LOG_STATS_NULLS
#define LOG_STATS_NULLS
Definition: log-stats.c:53
LogFileCtx_
Definition: util-logopenfile.h:72
LogStatsFileCtx_
Definition: log-stats.c:59
util-privs.h
LogFileCtx_::Write
int(* Write)(const char *buffer, int buffer_len, struct LogFileCtx_ *fp)
Definition: util-logopenfile.h:88
LogStatsLogThread_
Definition: log-stats.c:64
LOGGER_STATS
@ LOGGER_STATS
Definition: suricata-common.h:482
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:85
LogStatsLogThread
struct LogStatsLogThread_ LogStatsLogThread
util-unittest.h
LogStatsLogThreadInit
TmEcode LogStatsLogThreadInit(ThreadVars *, const void *, void **)
Definition: log-stats.c:166
ConfValIsTrue
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:537
OutputCtx_::data
void * data
Definition: tm-modules.h:87
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:84
OutputCtx_
Definition: tm-modules.h:84
SCConfLogOpenGeneric
int SCConfLogOpenGeneric(ConfNode *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:453
LogStatsLogThread_::buffer
MemBuffer * buffer
Definition: log-stats.c:66
util-debug.h
OutputInitResult_::ctx
OutputCtx * ctx
Definition: output.h:47
util-print.h
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
StatsRecord_::name
const char * name
Definition: output-stats.h:32
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
pkt-var.h
util-time.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:83
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:288
MemBufferReset
#define MemBufferReset(mem_buffer)
Reset the mem buffer.
Definition: util-buffer.h:42
OutputInitResult_
Definition: output.h:46
DEFAULT_LOG_FILENAME
#define DEFAULT_LOG_FILENAME
Definition: log-stats.c:47
suricata-common.h
OutputCtx_::DeInit
void(* DeInit)(struct OutputCtx_ *)
Definition: tm-modules.h:90
LogStatsLogThread_::statslog_ctx
LogStatsFileCtx * statslog_ctx
Definition: log-stats.c:65
MODULE_NAME
#define MODULE_NAME
Definition: log-stats.c:48
MemBufferFree
void MemBufferFree(MemBuffer *buffer)
Definition: util-buffer.c:87
StatsRecord_::tm_name
const char * tm_name
Definition: output-stats.h:34
MemBufferWriteString
#define MemBufferWriteString(dst,...)
Write a string buffer to the Membuffer dst.
Definition: util-buffer.h:162
LogFileFreeCtx
int LogFileFreeCtx(LogFileCtx *lf_ctx)
LogFileFreeCtx() Destroy a LogFileCtx (Close the file and free memory)
Definition: util-logopenfile.c:862
StatsTable_::tstats
StatsRecord * tstats
Definition: output-stats.h:41
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
threadvars.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ConfNode_
Definition: conf.h:32
LogStatsFileCtx_::flags
uint32_t flags
Definition: log-stats.c:61
util-logopenfile.h
MEMBUFFER_SIZE
#define MEMBUFFER_SIZE(mem_buffer)
Get the MemBuffers current size.
Definition: util-buffer.h:60
util-buffer.h
LOG_STATS_TOTALS
#define LOG_STATS_TOTALS
Definition: log-stats.c:51
ConfValIsFalse
int ConfValIsFalse(const char *val)
Check if a value is false.
Definition: conf.c:562
LOG_STATS_THREADS
#define LOG_STATS_THREADS
Definition: log-stats.c:52
MEMBUFFER_BUFFER
#define MEMBUFFER_BUFFER(mem_buffer)
Get the MemBuffers underlying buffer.
Definition: util-buffer.h:50
MEMBUFFER_OFFSET
#define MEMBUFFER_OFFSET(mem_buffer)
Get the MemBuffers current offset.
Definition: util-buffer.h:55
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
StatsTable_::nstats
uint32_t nstats
Definition: output-stats.h:42
OutputRegisterStatsModule
void OutputRegisterStatsModule(LoggerId id, const char *name, const char *conf_name, OutputInitFunc InitFunc, StatsLogger StatsLogFunc, ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit, ThreadExitPrintStatsFunc ThreadExitPrintStats)
Register a stats data output module.
Definition: output.c:709
MemBufferCreateNew
MemBuffer * MemBufferCreateNew(uint32_t size)
Definition: util-buffer.c:32
output.h
ConfNodeLookupChildValue
const char * ConfNodeLookupChildValue(const ConfNode *node, const char *name)
Lookup the value of a child configuration node by name.
Definition: conf.c:814