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