textlog.c 4.63 KB
Newer Older
1
2
#include "logger.h"
#include "logger_defs.h"
3
4
5
6
#include "handler.h"
#include "database.h"
#include "view/view.h"
#include "utils.h"
Cedric Roux's avatar
Cedric Roux committed
7
#include "filter/filter.h"
8
9
10
11
12
13
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

enum format_item_type {
  INSTRING,
Cedric Roux's avatar
Cedric Roux committed
14
  INT, ULONG, STRING, BUFFER };
15
16
17
18
19
20
21
22
23
24
25
26

struct format_item {
  enum format_item_type type;
  union {
    /* INSTRING */
    char *s;
    /* others */
    int event_arg;
  };
};

struct textlog {
27
  struct logger common;
28
29
30
31
32
33
34
35
36
37
38
39
40
  char *format;
  void *database;
  /* parsed format string */
  struct format_item *f;
  int fsize;
  /* local output buffer */
  OBUF o;
};

static void _event(void *p, event e)
{
  struct textlog *l = p;
  int i;
Cedric Roux's avatar
Cedric Roux committed
41
42
43
44
#ifdef T_SEND_TIME
  struct tm *t;
  char tt[64];
#endif
45

Cedric Roux's avatar
Cedric Roux committed
46
47
48
  if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0)
    return;

49
50
  l->o.osize = 0;

Cedric Roux's avatar
Cedric Roux committed
51
52
53
#ifdef T_SEND_TIME
  t = localtime(&e.sending_time.tv_sec);
  /* round tv_nsec to nearest millisecond */
54
55
  sprintf(tt, "%2.2d:%2.2d:%2.2d.%9.9ld: ", t->tm_hour, t->tm_min, t->tm_sec,
      e.sending_time.tv_nsec);
Cedric Roux's avatar
Cedric Roux committed
56
57
58
  PUTS(&l->o, tt);
#endif

59
60
61
62
  for (i = 0; i < l->fsize; i++)
  switch(l->f[i].type) {
  case INSTRING: PUTS(&l->o, l->f[i].s); break;
  case INT:      PUTI(&l->o, e.e[l->f[i].event_arg].i); break;
Cedric Roux's avatar
Cedric Roux committed
63
  case ULONG:    PUTUL(&l->o, e.e[l->f[i].event_arg].ul); break;
64
65
66
67
68
69
70
71
72
  case STRING:   PUTS_CLEAN(&l->o, e.e[l->f[i].event_arg].s); break;
  case BUFFER:
    PUTS(&l->o, "{buffer size:");
    PUTI(&l->o, e.e[l->f[i].event_arg].bsize);
    PUTS(&l->o, "}");
    break;
  }
  PUTC(&l->o, 0);

73
74
  for (i = 0; i < l->common.vsize; i++)
    l->common.v[i]->append(l->common.v[i], l->o.obuf);
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
}

enum chunk_type { C_ERROR, C_STRING, C_ARG_NAME, C_EVENT_NAME };
struct chunk {
  enum chunk_type type;
  char *s;
  enum format_item_type it;
  int event_arg;
};

/* TODO: speed it up? */
static int find_argument(char *name, database_event_format f,
    enum format_item_type *it, int *event_arg)
{
  int i;
  for (i = 0; i < f.count; i++) if (!strcmp(name, f.name[i])) break;
  if (i == f.count) return 0;
  *event_arg = i;
  if (!strcmp(f.type[i], "int"))         *it = INT;
Cedric Roux's avatar
Cedric Roux committed
94
  else if (!strcmp(f.type[i], "ulong"))  *it = ULONG;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  else if (!strcmp(f.type[i], "string")) *it = STRING;
  else if (!strcmp(f.type[i], "buffer")) *it = BUFFER;
  else return 0;
  return 1;
}

static struct chunk next_chunk(char **s, database_event_format f)
{
  char *cur = *s;
  char *name;
  enum format_item_type it;
  int event_arg;

  /* argument in [ ] */
  if (*cur == '[') {
    *cur = 0;
    cur++;
    name = cur;
    /* no \ allowed there */
    while (*cur && *cur != ']' && *cur != '\\') cur++;
    if (*cur != ']') goto error;
    *cur = 0;
    cur++;
    *s = cur;
    if (find_argument(name, f, &it, &event_arg) == 0) goto error;
    return (struct chunk){type:C_ARG_NAME, s:name, it:it, event_arg:event_arg};
  }

  /* { } is name of event (anything in between is smashed) */
  if (*cur == '{') {
    *cur = 0;
    cur++;
    while (*cur && *cur != '}') cur++;
    if (*cur != '}') goto error;
    *cur = 0;
    cur++;
    *s = cur;
    return (struct chunk){type:C_EVENT_NAME};
  }

  /* anything but [ and { is raw string */
  /* TODO: deal with \ */
  name = cur;
  while (*cur && *cur != '[' && *cur != '{') cur++;
  *s = cur;
  return (struct chunk){type:C_STRING, s:name};

error:
  return (struct chunk){type:C_ERROR};
}

146
logger *new_textlog(event_handler *h, void *database,
147
148
149
150
151
152
153
154
155
    char *event_name, char *format)
{
  struct textlog *ret;
  int event_id;
  database_event_format f;
  char *cur;

  ret = calloc(1, sizeof(struct textlog)); if (ret == NULL) abort();

156
157
  ret->common.event_name = strdup(event_name);
  if (ret->common.event_name == NULL) abort();
158
159
160
161
162
  ret->format = strdup(format); if (ret->format == NULL) abort();
  ret->database = database;

  event_id = event_id_from_name(database, event_name);

163
  ret->common.handler_id = register_handler_function(h,event_id,_event,ret);
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

  f = get_format(database, event_id);

  /* we won't get more than strlen(format) "chunks" */
  ret->f = malloc(sizeof(struct format_item) * strlen(format));
  if (ret->f == NULL) abort();

  cur = ret->format;

  while (*cur) {
    struct chunk c = next_chunk(&cur, f);
    switch (c.type) {
    case C_ERROR: goto error;
    case C_STRING:
      ret->f[ret->fsize].type = INSTRING;
      ret->f[ret->fsize].s = c.s;
      break;
    case C_ARG_NAME:
      ret->f[ret->fsize].type = c.it;
      ret->f[ret->fsize].event_arg = c.event_arg;
      break;
    case C_EVENT_NAME:
      ret->f[ret->fsize].type = INSTRING;
187
      ret->f[ret->fsize].s = ret->common.event_name;
188
189
190
191
192
193
194
195
196
197
198
      break;
    }
    ret->fsize++;
  }

  return ret;

error:
  printf("%s:%d: bad format '%s'\n", __FILE__, __LINE__, format);
  abort();
}