diff options
author | Guillaume Friloux <guillaume.friloux@gmail.com> | 2013-12-18 14:07:27 +0100 |
---|---|---|
committer | Guillaume Friloux <guillaume.friloux@gmail.com> | 2013-12-18 14:07:27 +0100 |
commit | dbb099df5455a2932b9ed3b12258cff8faca513b (patch) | |
tree | 34ed6643ddf96c7864139bc6fd3e9f02def16139 /src | |
parent | 2c55710a9d04323fc698f49047432b3e231d2ca7 (diff) |
Rewrite of smman.
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/Makefile.mk | 11 | ||||
-rw-r--r-- | src/bin/conf.c | 85 | ||||
-rw-r--r-- | src/bin/config.c | 40 | ||||
-rw-r--r-- | src/bin/filter.c | 35 | ||||
-rw-r--r-- | src/bin/logfiles.c | 194 | ||||
-rw-r--r-- | src/bin/logmessages.c | 171 | ||||
-rw-r--r-- | src/bin/main.c | 128 | ||||
-rw-r--r-- | src/bin/rules.c | 307 | ||||
-rw-r--r-- | src/bin/send.c | 257 | ||||
-rw-r--r-- | src/bin/smman.h | 163 | ||||
-rw-r--r-- | src/bin/spy.c | 349 | ||||
-rw-r--r-- | src/bin/utils.c | 47 |
12 files changed, 186 insertions, 1601 deletions
diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 3767425..169a3ff 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk | |||
@@ -1,18 +1,13 @@ | |||
1 | MAINTAINERCLEANFILES += \ | 1 | MAINTAINERCLEANFILES += \ |
2 | src/bin/sds_horodatage/*.gc{no,da} | 2 | src/bin/*.gc{no,da} |
3 | 3 | ||
4 | bin_PROGRAMS += \ | 4 | bin_PROGRAMS += \ |
5 | src/bin/smman | 5 | src/bin/smman |
6 | 6 | ||
7 | src_bin_smman_SOURCES = \ | 7 | src_bin_smman_SOURCES = \ |
8 | src/bin/conf.c \ | ||
9 | src/bin/utils.c \ | ||
10 | src/bin/logfiles.c \ | ||
11 | src/bin/logmessages.c \ | ||
12 | src/bin/main.c \ | 8 | src/bin/main.c \ |
13 | src/bin/rules.c \ | 9 | src/bin/config.c \ |
14 | src/bin/send.c \ | 10 | src/bin/smman.h |
15 | src/bin/spy.c | ||
16 | src_bin_smman_CPPFLAGS = @BIN_CFLAGS@ $(EXTRA_CPPFLAGS) | 11 | src_bin_smman_CPPFLAGS = @BIN_CFLAGS@ $(EXTRA_CPPFLAGS) |
17 | src_bin_smman_LDFLAGS = @BIN_LIBS@ | 12 | src_bin_smman_LDFLAGS = @BIN_LIBS@ |
18 | src_bin_smman_LDADD = \ | 13 | src_bin_smman_LDADD = \ |
diff --git a/src/bin/conf.c b/src/bin/conf.c deleted file mode 100644 index c185f61..0000000 --- a/src/bin/conf.c +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "smman.h" | ||
20 | #include <Conf.h> | ||
21 | |||
22 | /** | ||
23 | * @brief This function will init libconf and ask to load our configuration | ||
24 | * file | ||
25 | * | ||
26 | * @return 0 | ||
27 | */ | ||
28 | int conf_load(void) | ||
29 | { | ||
30 | struct libconfig myconf; | ||
31 | |||
32 | strcpy(global_ESserver, "http://127.0.0.1:9200/logstash/events/"); | ||
33 | strcpy(global_rulesdir, "/etc/smman/rules.d/"); | ||
34 | strcpy(global_conf, "/etc/smman/smman.conf"); | ||
35 | strcpy(global_type, "syslog"); | ||
36 | gethostname(global_host, sizeof(global_host)); | ||
37 | |||
38 | einadom_rules = eina_log_domain_register("smman_rules" , EINA_COLOR_LIGHTRED); | ||
39 | einadom_spy = eina_log_domain_register("smman_spy" , EINA_COLOR_LIGHTRED); | ||
40 | einadom_logfiles = eina_log_domain_register("smman_logfiles", EINA_COLOR_LIGHTRED); | ||
41 | einadom_send = eina_log_domain_register("smman_send" , EINA_COLOR_LIGHTRED); | ||
42 | einadom_conf = eina_log_domain_register("smman_conf" , EINA_COLOR_LIGHTRED); | ||
43 | |||
44 | libconfig_init(global_conf, &myconf); | ||
45 | libconfig_load(&myconf); | ||
46 | |||
47 | libconfig_list(&myconf, conf_load_var); | ||
48 | |||
49 | libconfig_free(&myconf); | ||
50 | return(0); | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * @brief This function is a callback for libconf, and receives a variable + | ||
55 | * its value found in a configuration file | ||
56 | * | ||
57 | * @param variable (char *) Variable's name | ||
58 | * @param value (char *) Variable's value | ||
59 | * | ||
60 | * @return 0 | ||
61 | */ | ||
62 | int conf_load_var(char *variable, char *value) | ||
63 | { | ||
64 | if( !strcmp(variable, "server") ) | ||
65 | { | ||
66 | EINA_LOG_DOM_DBG(einadom_conf, "Setting ES server to %s", variable); | ||
67 | strcpy(global_ESserver, value); | ||
68 | } | ||
69 | else if( !strcmp(variable, "host") ) | ||
70 | { | ||
71 | EINA_LOG_DOM_DBG(einadom_conf, "Setting default hostname to %s", variable); | ||
72 | strcpy(global_host, value); | ||
73 | } | ||
74 | else if( !strcmp(variable, "type") ) | ||
75 | { | ||
76 | EINA_LOG_DOM_DBG(einadom_conf, "Setting default type to %s", variable); | ||
77 | strcpy(global_type, value); | ||
78 | } | ||
79 | else | ||
80 | { | ||
81 | EINA_LOG_DOM_ERR(einadom_conf, "Unknown config variable %s", variable); | ||
82 | } | ||
83 | |||
84 | return(0); | ||
85 | } | ||
diff --git a/src/bin/config.c b/src/bin/config.c new file mode 100644 index 0000000..65b2637 --- /dev/null +++ b/src/bin/config.c | |||
@@ -0,0 +1,40 @@ | |||
1 | #include "smman.h" | ||
2 | |||
3 | void | ||
4 | config_done(void *data, | ||
5 | Conf *conf) | ||
6 | { | ||
7 | Smman *smman; | ||
8 | Eina_Iterator *it; | ||
9 | |||
10 | smman = data; | ||
11 | |||
12 | it = eina_hash_iterator_tuple_new(conf_variables_get(conf)); | ||
13 | while (eina_iterator_next(it, &data)) | ||
14 | { | ||
15 | const char *variable, | ||
16 | *value; | ||
17 | Eina_Hash_Tuple *t = data; | ||
18 | |||
19 | variable = t->key; | ||
20 | value = t->data; | ||
21 | |||
22 | if (!strcmp("server", variable)) | ||
23 | smman->cfg.server = strdup(value); | ||
24 | else if (!strcmp("host", variable)) | ||
25 | smman->cfg.host = strdup(value); | ||
26 | } | ||
27 | |||
28 | DBG("Server = %s", smman->cfg.server); | ||
29 | DBG("Host = %s", smman->cfg.host); | ||
30 | eina_iterator_free(it); | ||
31 | } | ||
32 | |||
33 | void | ||
34 | config_error(void *data EINA_UNUSED, | ||
35 | Conf *conf EINA_UNUSED, | ||
36 | const char *errstr) | ||
37 | { | ||
38 | ERR("Failed to load /etc/smman/smman.conf : %s", errstr); | ||
39 | ecore_main_loop_quit(); | ||
40 | } | ||
diff --git a/src/bin/filter.c b/src/bin/filter.c new file mode 100644 index 0000000..f5095ed --- /dev/null +++ b/src/bin/filter.c | |||
@@ -0,0 +1,35 @@ | |||
1 | #include "smman.h" | ||
2 | |||
3 | void | ||
4 | filter_load(void *data, | ||
5 | Rules *rules, | ||
6 | Rule *rule) | ||
7 | { | ||
8 | |||
9 | |||
10 | } | ||
11 | |||
12 | void | ||
13 | filter_load_done(void *data, | ||
14 | Rules *rules) | ||
15 | { | ||
16 | |||
17 | |||
18 | } | ||
19 | |||
20 | |||
21 | void | ||
22 | filter_load_error(void *data, | ||
23 | Rules *rules, | ||
24 | const char *errstr) | ||
25 | { | ||
26 | Smman *smman; | ||
27 | |||
28 | smman = data; | ||
29 | |||
30 | if (smman->rules != rules) | ||
31 | return; | ||
32 | |||
33 | ERR("Failed to load rules : %s", errstr); | ||
34 | ecore_main_loop_quit(); | ||
35 | } | ||
diff --git a/src/bin/logfiles.c b/src/bin/logfiles.c deleted file mode 100644 index c8f08a8..0000000 --- a/src/bin/logfiles.c +++ /dev/null | |||
@@ -1,194 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include "config.h" | ||
21 | #endif | ||
22 | |||
23 | |||
24 | #include "smman.h" | ||
25 | |||
26 | /** | ||
27 | * @brief Checks in the list of log files we are watching if we | ||
28 | * already watch a given logfile | ||
29 | * | ||
30 | * @param logfile (char *) Name of the logfile to check | ||
31 | * | ||
32 | * @return 0 if not found, 1 if found | ||
33 | */ | ||
34 | int logfiles_exist(char *logfile) | ||
35 | { | ||
36 | Eina_List *l; | ||
37 | struct logfile *foundlogfile = NULL; | ||
38 | EINA_LIST_FOREACH(list_logfiles, l, foundlogfile) | ||
39 | { | ||
40 | if( !strcmp(foundlogfile->name, logfile) ) | ||
41 | { | ||
42 | return(1); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | return(0); | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * @brief Adds a logfile struct inside the logfiles list | ||
51 | * | ||
52 | * @param new_logfile (struct logfile *) structure to add | ||
53 | * | ||
54 | * @return 0 if not found, 1 if found | ||
55 | */ | ||
56 | int logfiles_add(struct logfile *new_logfile) | ||
57 | { | ||
58 | list_logfiles = eina_list_append(list_logfiles, new_logfile); | ||
59 | return(0); | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * @brief Prints on stdout the list of logfiles. Only usefull for a bit of | ||
64 | * monitoring of what is going on | ||
65 | * | ||
66 | * @return 0 if not found, 1 if found | ||
67 | */ | ||
68 | int logfiles_print(void) | ||
69 | { | ||
70 | Eina_List *l; | ||
71 | struct logfile *foundlogfile = NULL; | ||
72 | EINA_LIST_FOREACH(list_logfiles, l, foundlogfile) | ||
73 | { | ||
74 | EINA_LOG_DOM_INFO(einadom_logfiles, "Name = %s", foundlogfile->name); | ||
75 | } | ||
76 | return(0); | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * @brief Will alloc a new logfile structure and set given values | ||
81 | * | ||
82 | * @param new_logfile (struct logfile *) structure to alloc | ||
83 | * @param filename (char *) Name of the logfile | ||
84 | * @param cursor (fpos_t) Position of the cursor | ||
85 | * @param filesize (unsigned long long int) Size of the file | ||
86 | * | ||
87 | * @return 0 | ||
88 | */ | ||
89 | int logfiles_new(struct logfile **new_logfile, char *filename, fpos_t cursor, unsigned long long int filesize) | ||
90 | { | ||
91 | *new_logfile = malloc(sizeof(struct logfile)); | ||
92 | (*new_logfile)->name = malloc(sizeof(char) * ( strlen(filename) + 1 ) ); | ||
93 | strcpy( (*new_logfile)->name, filename); | ||
94 | (*new_logfile)->cursor = cursor; | ||
95 | (*new_logfile)->filesize = filesize; | ||
96 | |||
97 | return(0); | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * @brief This function will free an allocated logfile structure | ||
102 | * | ||
103 | * @param old_logfile (struct logfile **) structure to free | ||
104 | * | ||
105 | * @return 0 | ||
106 | */ | ||
107 | int logfiles_del(struct logfile **old_logfile) | ||
108 | { | ||
109 | if( !(*old_logfile) ) | ||
110 | return(0); | ||
111 | |||
112 | if( (*old_logfile)->name ) | ||
113 | free((*old_logfile)->name); | ||
114 | |||
115 | free((*old_logfile)); | ||
116 | return(0); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * @brief This function will get a cursor to the end of the file | ||
121 | * | ||
122 | * @param logfile (char *) logfile involved | ||
123 | * @param pos_end (fpos_t *) pointer used to store the position | ||
124 | * | ||
125 | * @return 0 or -1 if an error occur | ||
126 | */ | ||
127 | int logfiles_getend(char *logfile, fpos_t *pos_end) | ||
128 | { | ||
129 | FILE *fp; | ||
130 | |||
131 | // We get our cursor pos | ||
132 | fp = fopen(logfile, "r"); | ||
133 | if( !fp ) | ||
134 | { | ||
135 | EINA_LOG_DOM_ERR(einadom_logfiles, "Can't open %s : %s", logfile, strerror(errno)); | ||
136 | return(-1); | ||
137 | } | ||
138 | fseeko(fp, 0L, SEEK_END); | ||
139 | fgetpos(fp, pos_end); | ||
140 | |||
141 | fclose(fp); | ||
142 | return(0); | ||
143 | } | ||
144 | |||
145 | /** | ||
146 | * @brief This function will get a cursor to the begin of the file | ||
147 | * | ||
148 | * @param logfile (char *) logfile involved | ||
149 | * @param pos_begin (fpos_t *) pointer used to store the position | ||
150 | * | ||
151 | * @return 0 or -1 if an error occur | ||
152 | */ | ||
153 | int logfiles_getbegin(char *logfile, fpos_t *pos_begin) | ||
154 | { | ||
155 | FILE *fp; | ||
156 | |||
157 | // We get our cursor pos | ||
158 | fp = fopen(logfile, "r"); | ||
159 | if( !fp ) | ||
160 | { | ||
161 | EINA_LOG_DOM_ERR(einadom_logfiles, "Can't open %s : %s", logfile, strerror(errno)); | ||
162 | return(-1); | ||
163 | } | ||
164 | fgetpos(fp, pos_begin); | ||
165 | |||
166 | fclose(fp); | ||
167 | return(0); | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * @brief This function will get the size of a file | ||
172 | * | ||
173 | * @param logfile (char *) logfile involved | ||
174 | * @param filesize (unsigned long long int) pointer used to store the size | ||
175 | * | ||
176 | * @return 0 or -1 if an error occur | ||
177 | */ | ||
178 | int logfiles_getsize(char *logfile, unsigned long long int *filesize) | ||
179 | { | ||
180 | struct stat64 st_buffer; | ||
181 | int retour; | ||
182 | |||
183 | retour = stat64(logfile, &st_buffer); | ||
184 | |||
185 | if( retour ) | ||
186 | { | ||
187 | EINA_LOG_DOM_ERR(einadom_logfiles, "Can't get size of %s : %s", logfile, strerror(errno)); | ||
188 | return(-1); | ||
189 | } | ||
190 | |||
191 | *filesize = st_buffer.st_size; | ||
192 | |||
193 | return(0); | ||
194 | } | ||
diff --git a/src/bin/logmessages.c b/src/bin/logmessages.c deleted file mode 100644 index aece58c..0000000 --- a/src/bin/logmessages.c +++ /dev/null | |||
@@ -1,171 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "smman.h" | ||
20 | |||
21 | /** | ||
22 | * @brief This function will init a given logmessage structure with default values | ||
23 | * | ||
24 | * @param new_logmessage (struct logmessage **) struct to alloc | ||
25 | * @param message (char *) Log message to store in this structure | ||
26 | * @param logname (char *) Name of the log file | ||
27 | * | ||
28 | * @return 0 | ||
29 | */ | ||
30 | int logmessages_new(struct logmessage **new_logmessage, char *message, char *logname) | ||
31 | { | ||
32 | *new_logmessage = malloc(sizeof(struct logmessage)); | ||
33 | |||
34 | if( message ) | ||
35 | { | ||
36 | (*new_logmessage)->message = malloc( sizeof(char) * ( strlen(message) + 1) ); | ||
37 | strcpy((*new_logmessage)->message, message); | ||
38 | } | ||
39 | else | ||
40 | { | ||
41 | (*new_logmessage)->message = malloc( sizeof(char) * (1) ); | ||
42 | (*new_logmessage)->message[0] = 0; | ||
43 | } | ||
44 | (*new_logmessage)->source_path = malloc( sizeof(char) * ( strlen(logname) + 1 ) ); | ||
45 | strcpy( (*new_logmessage)->source_path, logname); | ||
46 | |||
47 | (*new_logmessage)->source_host = malloc( sizeof(char) * ( strlen(global_host) + 1 ) ); | ||
48 | strcpy( (*new_logmessage)->source_host, global_host); | ||
49 | |||
50 | (*new_logmessage)->type = malloc( sizeof(char) * ( strlen(global_type) + 1 ) ); | ||
51 | strcpy( (*new_logmessage)->type, global_type); | ||
52 | |||
53 | (*new_logmessage)->timestamp = utils_date(); | ||
54 | |||
55 | (*new_logmessage)->list_tags = NULL; | ||
56 | (*new_logmessage)->todel = 0; | ||
57 | return(0); | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * @brief This function will free everything allocated in the structure | ||
62 | * | ||
63 | * @param old_logmessage (struct logmessage **) struct to free | ||
64 | * | ||
65 | * @return 0 | ||
66 | */ | ||
67 | int logmessages_free(struct logmessage **old_logmessage) | ||
68 | { | ||
69 | char *ptr; | ||
70 | if( (*old_logmessage)->source_host ) | ||
71 | free( (*old_logmessage)->source_host); | ||
72 | free( (*old_logmessage)->source_path); | ||
73 | free( (*old_logmessage)->type); | ||
74 | free( (*old_logmessage)->message); | ||
75 | free( (*old_logmessage)->timestamp); | ||
76 | |||
77 | EINA_LIST_FREE( (*old_logmessage)->list_tags, ptr) | ||
78 | free(ptr); | ||
79 | free( (*old_logmessage)); | ||
80 | return(0); | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * @brief This function will set a given type to a given logmessage structure | ||
85 | * | ||
86 | * @param mylog (struct logmessage *) Structure to modify | ||
87 | * @param type (char *) Type to set | ||
88 | * | ||
89 | * @return 0 | ||
90 | */ | ||
91 | int logmessages_set_type(struct logmessage *mylog, char *type) | ||
92 | { | ||
93 | if( mylog->type ) | ||
94 | free(mylog->type); | ||
95 | |||
96 | mylog->type = malloc( sizeof(char) * ( strlen(type) + 1 ) ); | ||
97 | strcpy(mylog->type, type); | ||
98 | return(0); | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * @brief This function will set a given host to a given logmessage structure | ||
103 | * | ||
104 | * @param mylog (struct logmessage *) Structure to modify | ||
105 | * @param source_host (char *) Host to set | ||
106 | * | ||
107 | * @return 0 | ||
108 | */ | ||
109 | int logmessages_set_sourcehost(struct logmessage *mylog, char *source_host) | ||
110 | { | ||
111 | if( mylog->source_host ) | ||
112 | free(mylog->source_host); | ||
113 | |||
114 | mylog->source_host = malloc( sizeof(char) * ( strlen(source_host) + 1 ) ); | ||
115 | strcpy(mylog->source_host, source_host); | ||
116 | return(0); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * @brief This function will add tags to the given logmessage structure. | ||
121 | * Tags has to be separated by a "," | ||
122 | * | ||
123 | * @param mylog (struct logmessage *) Structure to modify | ||
124 | * @param tag (char *) tag to add | ||
125 | * | ||
126 | * @return 0 | ||
127 | */ | ||
128 | int logmessages_add_tag(struct logmessage *mylog, char *tag) | ||
129 | { | ||
130 | char *ptr, | ||
131 | *ptr_delim; | ||
132 | int last = 0; | ||
133 | ptr = &tag[0]; | ||
134 | |||
135 | while( 1 ) | ||
136 | { | ||
137 | char *new_tag; | ||
138 | ptr_delim = strchr(ptr, ','); | ||
139 | if( !ptr_delim ) | ||
140 | { | ||
141 | ptr_delim = &ptr[strlen(ptr)+1]; | ||
142 | last = 1; | ||
143 | } | ||
144 | else ptr_delim[0] = 0; | ||
145 | |||
146 | new_tag = malloc( sizeof(char) * ( strlen(ptr) + 1 ) ); | ||
147 | strcpy(new_tag, ptr); | ||
148 | |||
149 | mylog->list_tags = eina_list_append(mylog->list_tags, new_tag); | ||
150 | |||
151 | if( last ) break; | ||
152 | ptr_delim[0] = ','; | ||
153 | ptr = &ptr_delim[1]; | ||
154 | } | ||
155 | |||
156 | return(0); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * @brief This function will set a given value to the delete field | ||
161 | * | ||
162 | * @param mylog (struct logmessage *) Structure to modify | ||
163 | * @param value (int) value to set | ||
164 | * | ||
165 | * @return 0 | ||
166 | */ | ||
167 | int logmessages_set_todel(struct logmessage *mylog, int value) | ||
168 | { | ||
169 | mylog->todel = value; | ||
170 | return(0); | ||
171 | } | ||
diff --git a/src/bin/main.c b/src/bin/main.c index 0e739ff..e7f0ece 100644 --- a/src/bin/main.c +++ b/src/bin/main.c | |||
@@ -18,60 +18,108 @@ | |||
18 | 18 | ||
19 | #include "smman.h" | 19 | #include "smman.h" |
20 | 20 | ||
21 | void _usage(char *progname) | 21 | static const Ecore_Getopt optdesc = { |
22 | "smman", | ||
23 | "%prog", | ||
24 | PACKAGE_VERSION, | ||
25 | "(C) Guillaume Friloux <kuri@efl.so>", | ||
26 | "GPL v2.", | ||
27 | " _______ \n" | ||
28 | " | _ |.--------..--------..---.-..-----.\n" | ||
29 | " | 1___|| || || _ || |\n" | ||
30 | " |____ ||__|__|__||__|__|__||___._||__|__|\n" | ||
31 | " |: 1 | \n" | ||
32 | " |::.. . | \n" | ||
33 | " `-------' \n", | ||
34 | 0, | ||
35 | { | ||
36 | ECORE_GETOPT_STORE_TRUE('d', "debug", "Runs smman in debug mode."), | ||
37 | ECORE_GETOPT_LICENSE('L', "license"), | ||
38 | ECORE_GETOPT_COPYRIGHT('C', "copyright"), | ||
39 | ECORE_GETOPT_VERSION('V', "version"), | ||
40 | ECORE_GETOPT_HELP('h', "help"), | ||
41 | ECORE_GETOPT_SENTINEL | ||
42 | } | ||
43 | }; /* ASCII ART : http://patorjk.com/software/taag/ - Font Cricket */ | ||
44 | |||
45 | |||
46 | Smman * | ||
47 | init(void) | ||
22 | { | 48 | { |
23 | printf(" _______ \n"); | 49 | Smman *smman; |
24 | printf(" | _ |.--------..--------..---.-..-----.\n"); | 50 | |
25 | printf(" | 1___|| || || _ || |\n"); | 51 | smman_log_dom_global = eina_log_domain_register("smman", EINA_COLOR_YELLOW); |
26 | printf(" |____ ||__|__|__||__|__|__||___._||__|__|\n"); | 52 | if (smman_log_dom_global < 0) |
27 | printf(" |: 1 | \n"); | 53 | { |
28 | printf(" |::.. . | Usage for %s : \n", progname); | 54 | EINA_LOG_ERR("Smman can not create a general log domain"); |
29 | printf(" `-------' \n"); | 55 | return NULL; |
30 | printf("\t--help\t\t-h :\tShow this help screen\n"); | 56 | } |
31 | printf("\t--version\t-v :\tShow revision version\n"); | 57 | |
32 | printf("\n"); | 58 | smman = calloc(1, sizeof(Smman)); |
33 | printf("\tDebugging : \n"); | 59 | if (!smman) |
34 | printf("\t\tEINA_LOG_LEVEL=5 %s\n", progname); | 60 | { |
61 | ERR("Failed to allocate smman structure"); | ||
62 | return NULL; | ||
63 | } | ||
64 | |||
65 | smman->rules = rules_new("/etc/smman/rules.d/"); | ||
66 | if (!smman->rules) | ||
67 | { | ||
68 | ERR("Failed to allocate new Rules structure"); | ||
69 | return NULL; | ||
70 | } | ||
71 | |||
72 | return smman; | ||
35 | } | 73 | } |
36 | 74 | ||
37 | int main(int argc, char **argv) | 75 | int main(int argc, char **argv) |
38 | { | 76 | { |
39 | int c; | 77 | Smman *smman; |
78 | Eina_Bool opt_quit = EINA_FALSE, | ||
79 | opt_debug = EINA_FALSE; | ||
80 | int opt_ind; | ||
81 | |||
40 | eina_init(); | 82 | eina_init(); |
41 | ecore_init(); | 83 | ecore_init(); |
42 | ecore_file_init(); | ||
43 | 84 | ||
44 | send_connected = EINA_FALSE; | 85 | Ecore_Getopt_Value values[] = { |
86 | ECORE_GETOPT_VALUE_BOOL(opt_debug), | ||
87 | ECORE_GETOPT_VALUE_BOOL(opt_quit), | ||
88 | ECORE_GETOPT_VALUE_BOOL(opt_quit), | ||
89 | ECORE_GETOPT_VALUE_BOOL(opt_quit), | ||
90 | ECORE_GETOPT_VALUE_BOOL(opt_quit), | ||
91 | ECORE_GETOPT_VALUE_NONE | ||
92 | }; | ||
45 | 93 | ||
46 | while (1) | 94 | opt_ind = ecore_getopt_parse(&optdesc, values, argc, argv); |
95 | if (opt_ind<0) | ||
47 | { | 96 | { |
48 | int option_index = 0; | 97 | EINA_LOG_ERR("Failed to parse args"); |
49 | 98 | return 1; | |
50 | static struct option long_options[] = { | ||
51 | {"help", 0, 0, 'h'}, | ||
52 | {0, 0, 0, 0} | ||
53 | }; | ||
54 | |||
55 | c = getopt_long(argc, argv, "h", long_options, &option_index); | ||
56 | if (c == -1) break; | ||
57 | |||
58 | switch (c) | ||
59 | { | ||
60 | case 'h': | ||
61 | _usage(argv[0]); | ||
62 | exit(0); | ||
63 | default: | ||
64 | break; | ||
65 | } | ||
66 | } | 99 | } |
67 | 100 | ||
68 | conf_load(); | 101 | if (opt_quit) |
69 | rules_load(); | 102 | return 0; |
70 | rules_print(); | 103 | |
71 | spy_init(); | 104 | conf_init(); |
72 | logfiles_print(); | 105 | rules_init(); |
106 | |||
107 | smman = init(); | ||
108 | if (!smman) | ||
109 | return 1; | ||
110 | |||
111 | conf_load("/etc/smman/smman.conf", config_done, config_error, smman); | ||
112 | rules_load(smman->rules, filter_load, filter_load_done, | ||
113 | filter_load_error, smman); | ||
73 | 114 | ||
74 | ecore_main_loop_begin(); | 115 | ecore_main_loop_begin(); |
75 | 116 | ||
117 | rules_shutdown(); | ||
118 | conf_shutdown(); | ||
119 | ecore_shutdown(); | ||
120 | eina_log_domain_unregister(smman_log_dom_global); | ||
121 | smman_log_dom_global = -1; | ||
122 | eina_shutdown(); | ||
123 | |||
76 | return 0; | 124 | return 0; |
77 | } | 125 | } |
diff --git a/src/bin/rules.c b/src/bin/rules.c deleted file mode 100644 index fe3c6f5..0000000 --- a/src/bin/rules.c +++ /dev/null | |||
@@ -1,307 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "smman.h" | ||
20 | #include <Conf.h> | ||
21 | |||
22 | struct rule *rules_temp; /**< Pointer to a rule, used so rules_load_rule_loadspec() knowns which rule rules_load_rule() is processing */ | ||
23 | |||
24 | /** | ||
25 | * @fn int rules_load(void) | ||
26 | * @brief List the rules directory and loads every rule in it | ||
27 | * | ||
28 | * @return 0 if no error, -1 if can't open rules dir | ||
29 | */ | ||
30 | int rules_load(void) | ||
31 | { | ||
32 | DIR *fd; | ||
33 | struct dirent * entree; | ||
34 | |||
35 | list_rules = NULL; | ||
36 | |||
37 | // For every rule in rules directory, we will load it | ||
38 | fd = opendir(global_rulesdir); | ||
39 | if( !fd ) | ||
40 | { | ||
41 | EINA_LOG_DOM_ERR(einadom_rules, "Can't open rules directory %s : %s", global_rulesdir, strerror(errno)); | ||
42 | return(-1); | ||
43 | } | ||
44 | while((entree = readdir(fd)) != NULL) | ||
45 | { | ||
46 | if( !strcmp(entree->d_name, ".") ) continue; | ||
47 | if( !strcmp(entree->d_name, "..") ) continue; | ||
48 | |||
49 | EINA_LOG_DOM_DBG(einadom_rules, "Found rule file %s", entree->d_name); | ||
50 | |||
51 | rules_load_rule(entree->d_name); | ||
52 | } | ||
53 | |||
54 | closedir(fd); | ||
55 | return(0); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * @fn int rules_load_rule(char *rule_name) | ||
60 | * @brief This function receives the name of a rule file, and ask for libconf | ||
61 | * to analyze it | ||
62 | * | ||
63 | * @param rule_name (char *) name of the rule (filename) | ||
64 | * | ||
65 | * @return 0 | ||
66 | */ | ||
67 | int rules_load_rule(char *rule_name) | ||
68 | { | ||
69 | char full_path[512]; | ||
70 | struct libconfig myconf; | ||
71 | |||
72 | sprintf(full_path, "%s%s", global_rulesdir, rule_name); | ||
73 | |||
74 | libconfig_init(full_path, &myconf); | ||
75 | libconfig_load(&myconf); | ||
76 | |||
77 | // We have to make a new rule struct | ||
78 | rules_temp = malloc(sizeof(struct rule)); | ||
79 | |||
80 | rules_temp->name = malloc(sizeof(char) * ( strlen(rule_name) + 1 ) ); | ||
81 | strcpy(rules_temp->name, rule_name); | ||
82 | |||
83 | // We init default values for our struct | ||
84 | rules_temp->filename = NULL; | ||
85 | rules_temp->type = NULL; | ||
86 | rules_temp->source_host = NULL; | ||
87 | rules_temp->source_path = NULL; | ||
88 | rules_temp->tags = NULL; | ||
89 | rules_temp->todel = 0; | ||
90 | rules_temp->list_regex = NULL; | ||
91 | |||
92 | libconfig_list(&myconf, rules_load_rule_loadspec); | ||
93 | |||
94 | libconfig_free(&myconf); | ||
95 | |||
96 | // We insert our new rule in our eina rule list | ||
97 | list_rules = eina_list_append(list_rules, rules_temp); | ||
98 | return(0); | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * @fn int rules_load_rule_loadspec(char *variable, char *value) | ||
103 | * @brief This function is a callback used by libconf to send us | ||
104 | * every variable+value that libconf found in a rulefile | ||
105 | * | ||
106 | * @param variable (char *) variable's name | ||
107 | * @param value (char *) variable's value | ||
108 | * | ||
109 | * @return 0 | ||
110 | */ | ||
111 | int rules_load_rule_loadspec(char *variable, char *value) | ||
112 | { | ||
113 | if( !strcmp(variable, "filename") ) | ||
114 | { | ||
115 | rules_temp->filename = malloc(sizeof(char) * ( strlen(value) + 1 )); | ||
116 | strcpy(rules_temp->filename, value); | ||
117 | } | ||
118 | else if( ( !strcmp(variable, "message") ) | ||
119 | || ( !strcmp(variable, "message_match") ) | ||
120 | || ( !strcmp(variable, "message_unmatch") ) | ||
121 | ) | ||
122 | { | ||
123 | struct regex *tmp_regex; | ||
124 | int ret; | ||
125 | |||
126 | tmp_regex = malloc(sizeof(struct regex)); | ||
127 | |||
128 | ret = regcomp(&(tmp_regex->preg), value, REG_EXTENDED); | ||
129 | if( ret ) | ||
130 | { | ||
131 | EINA_LOG_DOM_ERR(einadom_rules, "Regcomp failed to compile regexp %s", value); | ||
132 | free(tmp_regex); | ||
133 | return(0); | ||
134 | } | ||
135 | |||
136 | tmp_regex->message = malloc(sizeof(char) * ( strlen(value) + 1 )); | ||
137 | strcpy(tmp_regex->message, value); | ||
138 | |||
139 | if( !strcmp(variable, "message_unmatch") ) | ||
140 | tmp_regex->must_match = 0; | ||
141 | else | ||
142 | tmp_regex->must_match = 1; | ||
143 | |||
144 | rules_temp->list_regex = eina_list_append(rules_temp->list_regex, tmp_regex); | ||
145 | } | ||
146 | else if( !strcmp(variable, "type") ) | ||
147 | { | ||
148 | rules_temp->type = malloc(sizeof(char) * ( strlen(value) + 1 )); | ||
149 | strcpy(rules_temp->type, value); | ||
150 | } | ||
151 | else if( !strcmp(variable, "source_host") ) | ||
152 | { | ||
153 | rules_temp->source_host = malloc(sizeof(char) * ( strlen(value) + 1 )); | ||
154 | strcpy(rules_temp->source_host, value); | ||
155 | } | ||
156 | else if( !strcmp(variable, "source_path") ) | ||
157 | { | ||
158 | rules_temp->source_path = malloc(sizeof(char) * ( strlen(value) + 1 )); | ||
159 | strcpy(rules_temp->source_path, value); | ||
160 | } | ||
161 | else if( !strcmp(variable, "tags") ) | ||
162 | { | ||
163 | rules_temp->tags = malloc(sizeof(char) * ( strlen(value) + 1 )); | ||
164 | strcpy(rules_temp->tags, value); | ||
165 | } | ||
166 | else if( !strcmp(variable, "delete") ) | ||
167 | { | ||
168 | rules_temp->todel = atoi(value); | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | EINA_LOG_DOM_ERR(einadom_rules, "Unknown variable name %s", variable); | ||
173 | } | ||
174 | return(0); | ||
175 | } | ||
176 | |||
177 | |||
178 | /** | ||
179 | * @fn int rules_print(void) | ||
180 | * @brief This function will print to stdout every rules that is in | ||
181 | * the rules list. | ||
182 | * | ||
183 | * @return 0 | ||
184 | */ | ||
185 | int rules_print(void) | ||
186 | { | ||
187 | Eina_List *l; | ||
188 | struct rule *foundrule = NULL; | ||
189 | |||
190 | EINA_LIST_FOREACH(list_rules, l, foundrule) | ||
191 | { | ||
192 | EINA_LOG_DOM_INFO(einadom_rules, | ||
193 | "\n[%s]\n" | ||
194 | "\tfilename\t= %s\n" | ||
195 | "\ttype\t\t= %s\n" | ||
196 | "\tsource_host\t= %s\n" | ||
197 | "\tsource_path\t= %s\n" | ||
198 | "\ttags\t\t= %s\n" | ||
199 | "\tdelete\t= %d\n\n", | ||
200 | foundrule->name, | ||
201 | foundrule->filename, | ||
202 | foundrule->type, | ||
203 | foundrule->source_host, | ||
204 | foundrule->source_path, | ||
205 | foundrule->tags, | ||
206 | foundrule->todel); | ||
207 | } | ||
208 | return(0); | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * @fn int rules_list(int (*callback)(struct rule *foundrule)) | ||
213 | * @brief This function will list every rule in the list, to send each | ||
214 | * item to the given callback | ||
215 | * | ||
216 | * @param callback (int *) Callback that will receive all the items | ||
217 | * | ||
218 | * @return 0 | ||
219 | */ | ||
220 | int rules_list(int (*callback)(struct rule *foundrule)) | ||
221 | { | ||
222 | Eina_List *l; | ||
223 | struct rule *foundrule = NULL; | ||
224 | |||
225 | EINA_LIST_FOREACH(list_rules, l, foundrule) | ||
226 | { | ||
227 | callback(foundrule); | ||
228 | } | ||
229 | return(0); | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * @fn int rules_filtermessage(struct logmessage *new_logmessage) | ||
235 | * @brief This function will get a log message, and apply all the rules | ||
236 | * on it before giving it back and filtered | ||
237 | * | ||
238 | * @param new_logmessage (struct logmessage *) | ||
239 | * | ||
240 | * @return 0 | ||
241 | */ | ||
242 | int rules_filtermessage(struct logmessage *new_logmessage) | ||
243 | { | ||
244 | Eina_List *l, *l2; | ||
245 | struct rule *foundrule = NULL; | ||
246 | struct regex *foundregex = NULL; | ||
247 | int ret, | ||
248 | excluded = 0; | ||
249 | |||
250 | // We check each rules to see what we have to do | ||
251 | EINA_LIST_FOREACH(list_rules, l, foundrule) | ||
252 | { | ||
253 | // If filename is set, we check that our log is affected | ||
254 | // By this rule's filename | ||
255 | if( foundrule->filename ) | ||
256 | { | ||
257 | ret = fnmatch(foundrule->filename, new_logmessage->source_path, FNM_NOESCAPE); | ||
258 | if( ret ) | ||
259 | { | ||
260 | EINA_LOG_DOM_DBG(einadom_rules, "Log \"%s\" from \"%s\" is not affected by rule %s (filename exclude)", new_logmessage->message, new_logmessage->source_path, foundrule->name); | ||
261 | continue; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | excluded = 0; | ||
266 | |||
267 | // For every regex affected to the rule, we apply it to the | ||
268 | // Log message we got to see if we have something to filter | ||
269 | EINA_LIST_FOREACH(foundrule->list_regex, l2, foundregex) | ||
270 | { | ||
271 | size_t nmatch = 2; | ||
272 | regmatch_t pmatch[2]; | ||
273 | |||
274 | ret = regexec(&(foundregex->preg), new_logmessage->message,nmatch, pmatch, 0); | ||
275 | |||
276 | // If regexec returns 0, then the log message matches the regex. | ||
277 | // If regexec returns 1, then the log message doesnt match the regex. | ||
278 | // So if the regex must match (message= or message_match= in rule, so must_match=1) or musnt match (message_unmatch=, must_match=0), | ||
279 | // We can consider that the message must be filtered if regex returns something different than 'must_match' | ||
280 | if( ret == foundregex->must_match ) | ||
281 | { | ||
282 | EINA_LOG_DOM_INFO(einadom_rules, "Log \"%s\" from \"%s\" is not affected by rule %s (message exclude : %s / %d / %d)", new_logmessage->message, new_logmessage->source_path, foundrule->name, foundregex->message, foundregex->must_match, ret); | ||
283 | excluded = 1; | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | if( excluded ) | ||
289 | continue; | ||
290 | |||
291 | // If we get here, then our log message have to be filtered | ||
292 | |||
293 | // If type is specified, then we have to override it | ||
294 | if( foundrule->type ) | ||
295 | logmessages_set_type(new_logmessage, foundrule->type); | ||
296 | |||
297 | if( foundrule->source_host ) | ||
298 | logmessages_set_sourcehost(new_logmessage, foundrule->source_host); | ||
299 | |||
300 | if( foundrule->tags ) | ||
301 | logmessages_add_tag(new_logmessage, foundrule->tags); | ||
302 | |||
303 | if( foundrule->todel ) | ||
304 | logmessages_set_todel(new_logmessage, 1); | ||
305 | } | ||
306 | return(0); | ||
307 | } | ||
diff --git a/src/bin/send.c b/src/bin/send.c deleted file mode 100644 index 422e7b1..0000000 --- a/src/bin/send.c +++ /dev/null | |||
@@ -1,257 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "smman.h" | ||
20 | |||
21 | CURL *curl; | ||
22 | CURLcode res; | ||
23 | |||
24 | /** | ||
25 | * @brief This function will receive a logmessage to index, | ||
26 | * convert it into JSON data and send it to <a href=www.elasticsearch.com>ES</a> | ||
27 | * | ||
28 | * @param new_logmessage (struct logmessage *) Log message to index | ||
29 | * | ||
30 | * @see send_convJSON() | ||
31 | * @see struct logmessage | ||
32 | * @see send_toES | ||
33 | * | ||
34 | * @return 0 | ||
35 | */ | ||
36 | int send_logmessage(struct logmessage *new_logmessage) | ||
37 | { | ||
38 | Eina_List *l; | ||
39 | char *tag = NULL, | ||
40 | *tags = NULL, | ||
41 | *jsondata = NULL; | ||
42 | unsigned int size = 0, | ||
43 | i = 0; | ||
44 | |||
45 | // We check how much space we need to store tags | ||
46 | EINA_LIST_FOREACH(new_logmessage->list_tags, l, tag) | ||
47 | { | ||
48 | size += strlen(tag) + 3; | ||
49 | } | ||
50 | |||
51 | tags = malloc( sizeof(char) * ( size + 1 ) ); | ||
52 | memset(tags, 0, size + 1); | ||
53 | |||
54 | EINA_LIST_FOREACH(new_logmessage->list_tags, l, tag) | ||
55 | { | ||
56 | if( i > 0 ) | ||
57 | strcat(tags, ","); | ||
58 | |||
59 | strcat(tags, "\""); | ||
60 | strcat(tags, tag); | ||
61 | strcat(tags, "\""); | ||
62 | i++; | ||
63 | } | ||
64 | // We will build our JSON object from these values | ||
65 | send_convJSON(new_logmessage->source_host, new_logmessage->source_path, new_logmessage->type, new_logmessage->message, tags, new_logmessage->timestamp, &jsondata); | ||
66 | |||
67 | EINA_LOG_DOM_DBG(einadom_send, "JSON : %s", jsondata); | ||
68 | |||
69 | send_toES(jsondata); | ||
70 | |||
71 | free(jsondata); | ||
72 | free(tags); | ||
73 | return(0); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * @brief This Function receives all needed vars to build the JSON data for <a href=www.elasticsearch.com>ES</a>. | ||
78 | * @warning This function will malloc jsondata, so dont do it yourself, and dont forget to free it! | ||
79 | * | ||
80 | * @param source_host (char *) Host that sent the logfile | ||
81 | * @param source_path (char *) Logfile name | ||
82 | * @param type (char *) Type for this log message | ||
83 | * @param message (char *) Log message | ||
84 | * @param tags (char *) list of tags, they must be already parsed in format "Tag1","Tag2","Tag3" | ||
85 | * @param timestamp (char *) Timestamp for the message | ||
86 | * @param jsondata (char **) Buffer that we will malloc and fill with generated JSON message | ||
87 | * | ||
88 | * @return 0 | ||
89 | */ | ||
90 | int send_convJSON(char *source_host, char *source_path, char *type, char *message, char *tags, char *timestamp, char **jsondata) | ||
91 | { | ||
92 | char *Esource_host = NULL, | ||
93 | *Esource_path = NULL, | ||
94 | *Etype = NULL, | ||
95 | *Emessage = NULL; | ||
96 | |||
97 | send_escape(source_host, &Esource_host); | ||
98 | send_escape(source_path, &Esource_path); | ||
99 | send_escape(type, &Etype); | ||
100 | send_escape(message, &Emessage); | ||
101 | |||
102 | *jsondata = malloc( sizeof(char) * (200 + strlen(Esource_host)*2 + strlen(Esource_path)*2 + strlen(Etype) + strlen(Emessage) + strlen(tags) + 30 + 1) ); | ||
103 | sprintf(*jsondata, | ||
104 | "{" | ||
105 | " \"@source\" : \"file://%s%s\"," | ||
106 | " \"@type\" : \"%s\"," | ||
107 | " \"@tags\" : [ %s ]," | ||
108 | " \"@fields\" : { }," | ||
109 | " \"@message\" : \"%s\"," | ||
110 | " \"@timestamp\" : \"%s\"," | ||
111 | " \"@source_host\" : \"%s\"," | ||
112 | " \"@source_path\" : \"%s\"" | ||
113 | "}", | ||
114 | Esource_host, Esource_path, Etype, tags, Emessage, timestamp, Esource_host, Esource_path); | ||
115 | |||
116 | free(Esource_host); | ||
117 | free(Esource_path); | ||
118 | free(Etype); | ||
119 | free(Emessage); | ||
120 | |||
121 | return(0); | ||
122 | } | ||
123 | |||
124 | |||
125 | /** | ||
126 | * @brief This Function will escape all double quote so we dont get a parsing problem | ||
127 | * @warning This function will malloc dst, so dont do it yourself, and dont forget to free it! | ||
128 | * | ||
129 | * @param src (char *) buffer to escape | ||
130 | * @param dst (char **) Escaped buffer | ||
131 | * | ||
132 | * @return Pointer to escaped buffer | ||
133 | */ | ||
134 | char *send_escape(char *src, char **dst) | ||
135 | { | ||
136 | unsigned i = 0, | ||
137 | j = 0, | ||
138 | len = strlen(src); | ||
139 | char tmp[len*2+1]; | ||
140 | |||
141 | memset(tmp, 0, sizeof(tmp)); | ||
142 | |||
143 | for( i = 0; i < len+1; i++) | ||
144 | { | ||
145 | if( src[i] == '"') | ||
146 | tmp[j++] = '\\'; | ||
147 | tmp[j++] = src[i]; | ||
148 | } | ||
149 | *dst = malloc( sizeof(char) * ( strlen(tmp) + 1 ) ); | ||
150 | strcpy(*dst, tmp); | ||
151 | return(*dst); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * @brief Inits the curl object, and set necessary params | ||
156 | * | ||
157 | * @return 0 | ||
158 | */ | ||
159 | int send_init(void) | ||
160 | { | ||
161 | curl = curl_easy_init(); | ||
162 | if( !curl ) | ||
163 | { | ||
164 | EINA_LOG_DOM_ERR(einadom_send, "Can't init curl."); | ||
165 | return(-1); | ||
166 | } | ||
167 | curl_easy_setopt(curl, CURLOPT_NOPROGRESS, EINA_TRUE); | ||
168 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, send_fromES); | ||
169 | curl_easy_setopt(curl, CURLOPT_URL, global_ESserver); | ||
170 | send_connected = EINA_TRUE; | ||
171 | |||
172 | return(0); | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * @brief Destroys the curl object | ||
177 | * | ||
178 | * @return 0 | ||
179 | */ | ||
180 | int send_destroy(void) | ||
181 | { | ||
182 | curl_easy_cleanup(curl); | ||
183 | return(0); | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * @brief This function will send a given JSON data to the configured | ||
188 | * JSON server | ||
189 | * | ||
190 | * @param jsondata (char *) | ||
191 | * | ||
192 | * @return 0 | ||
193 | */ | ||
194 | int send_toES(char *jsondata) | ||
195 | { | ||
196 | /* ecore_con_url_post doesnt return any error if it cant send | ||
197 | which sucks for us. Waiting for patch coming for EFLs 1.1 | ||
198 | Ecore_Con_Url *ecu; | ||
199 | Eina_Bool ret; | ||
200 | |||
201 | ecore_con_url_init(); | ||
202 | ecu = ecore_con_url_new(global_ESserver); | ||
203 | if( !ecu ) | ||
204 | { | ||
205 | EINA_LOG_DOM_ERR(einadom_send, "Can't init ecore_con_url_new()"); | ||
206 | ecore_con_url_shutdown(); | ||
207 | return(-1); | ||
208 | } | ||
209 | |||
210 | ret = ecore_con_url_post(ecu, jsondata, -1, "text/xml"); | ||
211 | if( ret == EINA_FALSE ) | ||
212 | { | ||
213 | EINA_LOG_DOM_ERR(einadom_send, "Can't send jsondata to ES"); | ||
214 | ecore_con_url_shutdown(); | ||
215 | return(-1); | ||
216 | } | ||
217 | |||
218 | ecore_con_url_free(ecu); | ||
219 | ecore_con_url_shutdown(); | ||
220 | */ | ||
221 | if( send_connected == EINA_FALSE ) | ||
222 | { | ||
223 | send_init(); | ||
224 | } | ||
225 | |||
226 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsondata); | ||
227 | res = curl_easy_perform(curl); | ||
228 | if( res ) | ||
229 | { | ||
230 | EINA_LOG_DOM_ERR(einadom_send, "Sending of JSON query failed, curl returned : %d", res); | ||
231 | send_destroy(); | ||
232 | send_connected = EINA_FALSE; | ||
233 | } | ||
234 | |||
235 | return(0); | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * @brief This fonction will get response from <a href=www.elasticsearch.com>ES</A> | ||
240 | * after sending our JSON data. This function is a callback used by libcurl | ||
241 | * | ||
242 | * @param ptr (void *) To be defined | ||
243 | * @param size (size_t) To be defined | ||
244 | * @param nmemb (size_t) To be defined | ||
245 | * @param data (void *) To be defined | ||
246 | * | ||
247 | * @return Number of bytes received | ||
248 | */ | ||
249 | size_t send_fromES(void *ptr, | ||
250 | size_t size, | ||
251 | size_t nmemb, | ||
252 | void *data EINA_UNUSED) | ||
253 | { | ||
254 | if( strncmp((char *)ptr, "{\"ok\":", 6) ) | ||
255 | EINA_LOG_DOM_ERR(einadom_send, "Indexing of JSON data failed"); | ||
256 | return(size * nmemb); | ||
257 | } | ||
diff --git a/src/bin/smman.h b/src/bin/smman.h index 5cee0a8..62a273d 100644 --- a/src/bin/smman.h +++ b/src/bin/smman.h | |||
@@ -1,155 +1,32 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifdef HAVE_CONFIG_H | 1 | #ifdef HAVE_CONFIG_H |
20 | # include "config.h" | 2 | # include <config.h> |
21 | #endif | 3 | #endif |
22 | 4 | ||
23 | #include <Eina.h> | 5 | #include <Eina.h> |
24 | #include <Ecore.h> | 6 | #include <Ecore.h> |
25 | #include <Ecore_File.h> | 7 | #include <Ecore_Getopt.h> |
26 | #include <curl/curl.h> | 8 | #include <Eio.h> |
27 | 9 | #include <Conf.h> | |
28 | #include <dirent.h> | ||
29 | #include <errno.h> | ||
30 | #include <fnmatch.h> | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/stat.h> | ||
33 | #include <regex.h> | ||
34 | #include <unistd.h> | ||
35 | #include <libgen.h> | ||
36 | #include <getopt.h> | ||
37 | |||
38 | #ifndef GLOBALVARS | ||
39 | #define GLOBALVARS | ||
40 | char global_rulesdir[35], /**< Allows us to store the rules directory */ | ||
41 | global_conf[35], /**< Allows us to store the configuration directory */ | ||
42 | global_host[35], /**< Allows us to store the default hostname */ | ||
43 | global_type[35], /**< Allows us to store the default type */ | ||
44 | global_ESserver[128];/**< Allows us to store ElasticSearch server adress */ | ||
45 | |||
46 | /** | ||
47 | * @struct rule | ||
48 | * @brief This structure can handle a rule described in the rule directory | ||
49 | */ | ||
50 | struct rule | ||
51 | { | ||
52 | char *name, /**< Rule's name (Guessed using the filename of the rule inside the rules directory) */ | ||
53 | *filename,/**< It is the filename of the logfile(s) that match this rule (see this as a condition) */ | ||
54 | *type,/**< Type we will apply to the matched log message (see this as an affectation) */ | ||
55 | *source_host,/**< Host we will apply to the matched log message (see this as an affectation) */ | ||
56 | *source_path,/**< Log path we will apply to the matched log message (its like renaming the log, without mv it) (see this as an affectation) */ | ||
57 | *tags;/**< tags we will apply to the matched log message (see this as an affectation) */ | ||
58 | int todel;/**< If set to something other than 0, every matched rule will not be indexed */ | ||
59 | Eina_List *list_regex;/**< Regexps to apply to message we get from syslog, then match them (see this as a condition) */ | ||
60 | }; | ||
61 | |||
62 | /** | ||
63 | * @struct regex | ||
64 | * @brief This structure can handle a regex that will be compared to log messages | ||
65 | * in order to see if they are affected by a rule or not | ||
66 | */ | ||
67 | struct regex | ||
68 | { | ||
69 | char *message; | ||
70 | int must_match; | ||
71 | regex_t preg; | ||
72 | }; | ||
73 | 10 | ||
74 | /** | 11 | int smman_log_dom_global; |
75 | * @struct logfile | ||
76 | * @brief This structure allows us to attach a cursor position to a logfile, | ||
77 | * which is necessary to find new log entries | ||
78 | */ | ||
79 | struct logfile | ||
80 | { | ||
81 | char *name; /**< Name of the log file */ | ||
82 | fpos_t cursor; /**< Position of the cursor inside this logfile */ | ||
83 | unsigned long long int filesize; /**< File size, only help to see if a logfile is truncated, as far as i know */ | ||
84 | }; | ||
85 | 12 | ||
86 | /** | 13 | typedef struct _Smman |
87 | * @struct logmessage | ||
88 | * @brief This structure Contains needed information about a logfile that is going | ||
89 | * to be JSONed for ES. | ||
90 | */ | ||
91 | struct logmessage | ||
92 | { | 14 | { |
93 | char *source_host, /**< Hostname */ | 15 | Rules *rules; |
94 | *source_path, /**< Name of the logfile from where this message comes from */ | ||
95 | *timestamp, /**< Date of the log */ | ||
96 | *type, /**< Type of message */ | ||
97 | *message; /**< Log message to index in ES */ | ||
98 | Eina_List *list_tags; /**< List of tags associated to this message */ | ||
99 | int todel; /**< If set to something other than 0, this message wont be indexed */ | ||
100 | }; | ||
101 | |||
102 | int einadom_rules, /**< Used for eina_log inside rules.c */ | ||
103 | einadom_spy, /**< Used for eina_log inside spy.c */ | ||
104 | einadom_logfiles, /**< Used for eina_log inside logfiles.c */ | ||
105 | einadom_send, /**< Used for eina_log inside send.c */ | ||
106 | einadom_conf; /**< Used for eina_log inside conf.c */ | ||
107 | |||
108 | Eina_List *list_rules; /**< Used to store all the rules in memory, in an eina list */ | ||
109 | Eina_List *list_logfiles; /**< Used to store all the logfiles watched, in an eina list */ | ||
110 | Ecore_File_Monitor *efm; /**< Used for file monitoring by ecore */ | ||
111 | |||
112 | unsigned char send_connected; | ||
113 | #endif | ||
114 | |||
115 | int conf_load(void); | ||
116 | int conf_load_var(char *variable, char *value); | ||
117 | |||
118 | int logfiles_exist(char *logfile); | ||
119 | int logfiles_add(struct logfile *new_logfile); | ||
120 | int logfiles_print(void); | ||
121 | int logfiles_new(struct logfile **new_logfile, char *filename, fpos_t cursor, unsigned long long int filesize); | ||
122 | int logfiles_del(struct logfile **old_logfile); | ||
123 | int logfiles_getend(char *logfile, fpos_t *pos_end); | ||
124 | int logfiles_getbegin(char *logfile, fpos_t *pos_begin); | ||
125 | int logfiles_getsize(char *logfile, unsigned long long int *filesize); | ||
126 | |||
127 | int logmessages_new(struct logmessage **new_logmessage, char *message, char *logname); | ||
128 | int logmessages_free(struct logmessage **old_logmessage); | ||
129 | int logmessages_set_type(struct logmessage *mylog, char *type); | ||
130 | int logmessages_set_sourcehost(struct logmessage *mylog, char *source_host); | ||
131 | int logmessages_add_tag(struct logmessage *mylog, char *tag); | ||
132 | int logmessages_set_todel(struct logmessage *mylog, int value); | ||
133 | |||
134 | int rules_load(void); | ||
135 | int rules_load_rule(char *rule_name); | ||
136 | int rules_load_rule_loadspec(char *variable, char *value); | ||
137 | int rules_print(void); | ||
138 | int rules_list(int (*callback)(struct rule *foundrule)); | ||
139 | int rules_filtermessage(struct logmessage *new_logmessage); | ||
140 | 16 | ||
141 | int send_logmessage(struct logmessage *new_logmessage); | 17 | struct |
142 | int send_convJSON(char *source_host, char *source_path, char *type, char *message, char *tags, char *timestamp, char **jsondata); | 18 | { |
143 | char *send_escape(char *src, char **dst); | 19 | const char *server, |
144 | int send_toES(char *jsondata); | 20 | *host; |
145 | size_t send_fromES(void *ptr, size_t size, size_t nmemb, void *data); | 21 | } cfg; |
146 | int send_init(void); | 22 | } Smman; |
147 | int send_destroy(void); | ||
148 | 23 | ||
24 | #define ERR(...) EINA_LOG_DOM_ERR(smman_log_dom_global, __VA_ARGS__) | ||
25 | #define DBG(...) EINA_LOG_DOM_DBG(smman_log_dom_global, __VA_ARGS__) | ||
26 | #define NFO(...) EINA_LOG_DOM_INFO(smman_log_dom_global, __VA_ARGS__) | ||
27 | #define WRN(...) EINA_LOG_DOM_WARN(smman_log_dom_global, __VA_ARGS__) | ||
28 | #define CRI(...) EINA_LOG_DOM_CRIT(smman_log_dom_global, __VA_ARGS__) | ||
149 | 29 | ||
150 | int spy_init(void); | ||
151 | int spy_addwatcher(struct rule *foundrule); | ||
152 | int spy_event(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path); | ||
153 | int spy_extract_new_lines(char *filename, fpos_t pos_cur, fpos_t *pos_new, char *message); | ||
154 | 30 | ||
155 | char * utils_date(void); | 31 | void config_done(void *data, Conf *conf); |
32 | void config_error(void *data, Conf *conf, const char *errstr); | ||
diff --git a/src/bin/spy.c b/src/bin/spy.c deleted file mode 100644 index 6d27fde..0000000 --- a/src/bin/spy.c +++ /dev/null | |||
@@ -1,349 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "smman.h" | ||
20 | #include <wordexp.h> | ||
21 | |||
22 | |||
23 | /** | ||
24 | * @brief Will ask rules_list() to list all rules and tell spy_addwatcher() | ||
25 | * of every found rule so we can process it and monitor matching log files | ||
26 | * | ||
27 | * @return 0 | ||
28 | */ | ||
29 | int spy_init(void) | ||
30 | { | ||
31 | rules_list(spy_addwatcher); | ||
32 | return(0); | ||
33 | } | ||
34 | |||
35 | /** | ||
36 | * @brief Gets a rule in param, and will check for every matching | ||
37 | * files on the system | ||
38 | * | ||
39 | * @param foundrule (struct rule *) Rule found by rules_list() | ||
40 | * | ||
41 | * @return 0 if no error, -1 if any error | ||
42 | */ | ||
43 | int spy_addwatcher(struct rule *foundrule) | ||
44 | { | ||
45 | wordexp_t p; | ||
46 | int ret; | ||
47 | unsigned int i; | ||
48 | char *ptr, | ||
49 | tmp[512]; | ||
50 | |||
51 | if( !foundrule->filename ) | ||
52 | return(0); | ||
53 | |||
54 | // As filenames can contain wildcards, we have to test | ||
55 | // Globbing | ||
56 | ret = wordexp(foundrule->filename, &p, 0); | ||
57 | if( ret ) | ||
58 | { | ||
59 | EINA_LOG_DOM_ERR(einadom_spy, "l utilisation de wordexp() a echoue, il a renvoye %d", ret); | ||
60 | return(-1); | ||
61 | } | ||
62 | |||
63 | EINA_LOG_DOM_DBG(einadom_spy, "Found %zu results for %s", p.we_wordc, foundrule->filename); | ||
64 | |||
65 | // We now have a list of files (or a unique file) and we want to add them | ||
66 | // To our file list | ||
67 | for( i = 0; i < p.we_wordc; i++) | ||
68 | { | ||
69 | int exist = 0; | ||
70 | |||
71 | exist = logfiles_exist(p.we_wordv[i]); | ||
72 | |||
73 | if( !exist ) | ||
74 | { | ||
75 | fpos_t pos_tmp; | ||
76 | struct logfile *new_logfile; | ||
77 | unsigned long long int filesize = 0; | ||
78 | |||
79 | // We get our cursor pos | ||
80 | logfiles_getend(p.we_wordv[i], &pos_tmp); | ||
81 | logfiles_getsize(p.we_wordv[i], &filesize); | ||
82 | logfiles_new(&new_logfile, p.we_wordv[i], pos_tmp, filesize); | ||
83 | |||
84 | logfiles_add(new_logfile); | ||
85 | efm = ecore_file_monitor_add(p.we_wordv[i], | ||
86 | (Ecore_File_Monitor_Cb)spy_event, | ||
87 | (void *)new_logfile); | ||
88 | } | ||
89 | } | ||
90 | wordfree(&p); | ||
91 | |||
92 | // We will check parent directory to see if a new file is created | ||
93 | // and matches one of the rules when a CREATE event is raised. | ||
94 | // This part sucks cause we only watch the last directory while | ||
95 | // The wildcard can englob multiple directories! (and so our code gets totally buggy) | ||
96 | strncpy(tmp, foundrule->filename, 512); | ||
97 | ptr = dirname(tmp); | ||
98 | efm = ecore_file_monitor_add(ptr, | ||
99 | (Ecore_File_Monitor_Cb)spy_event, | ||
100 | NULL); | ||
101 | |||
102 | return(0); | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * @brief ecore_main_loop() will call this function for every notification he gets from logfiles | ||
107 | * activity. | ||
108 | * | ||
109 | * @param data (void *) Data associated to the logfile in spy_addwatcher() | ||
110 | * @param em (Ecore_File_Monitor *) Not really used here. | ||
111 | * @param event (Ecore_File_Event) Event type | ||
112 | * @param path (const char *) Name of the file that raised the event | ||
113 | * | ||
114 | * @return ECORE_CALLBACK_RENEW | ||
115 | */ | ||
116 | int spy_event(void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path) | ||
117 | { | ||
118 | struct logmessage *new_logmessage; | ||
119 | char message[4096]; | ||
120 | |||
121 | EINA_LOG_DOM_DBG(einadom_spy, "Event on %s ! %p - %p", path, data, em); | ||
122 | message[0] = 0; | ||
123 | |||
124 | if( event == ECORE_FILE_EVENT_MODIFIED ) | ||
125 | { | ||
126 | struct logfile *log = data; | ||
127 | fpos_t new_pos; | ||
128 | unsigned long long int filesize; | ||
129 | Eina_Counter *counter; | ||
130 | char *counterresult; | ||
131 | if( !log ) | ||
132 | return(ECORE_CALLBACK_RENEW); | ||
133 | counter = eina_counter_new("MessageProcessingTime"); | ||
134 | eina_counter_start(counter); | ||
135 | // If logfile got trunc, than size is different | ||
136 | logfiles_getsize((char *)path, &filesize); | ||
137 | |||
138 | if( filesize < log->filesize ) | ||
139 | { | ||
140 | // If event is that file has been truncated, then there is | ||
141 | // nothing to read, we just set cursor to beginning | ||
142 | logfiles_getbegin((char *)path, &(log->cursor)); | ||
143 | log->filesize = filesize; | ||
144 | return(ECORE_CALLBACK_RENEW); | ||
145 | } | ||
146 | log->filesize = filesize; | ||
147 | |||
148 | EINA_LOG_DOM_DBG(einadom_spy, "Event on %s !", path); | ||
149 | |||
150 | // We must take attention to the fact that the file might | ||
151 | // Have been truncated | ||
152 | spy_extract_new_lines(log->name, log->cursor, &new_pos, message); | ||
153 | log->cursor = new_pos; | ||
154 | |||
155 | // If nothing has been read, then file has been trunc and is empty | ||
156 | // So we do nothing | ||
157 | if( message[0] == 0 ) | ||
158 | return(ECORE_CALLBACK_RENEW); | ||
159 | |||
160 | logmessages_new(&new_logmessage, message, log->name); | ||
161 | |||
162 | rules_filtermessage(new_logmessage); | ||
163 | |||
164 | // Now we only have to send this filtered message to ES | ||
165 | if( !new_logmessage->todel ) | ||
166 | send_logmessage(new_logmessage); | ||
167 | |||
168 | // Message is sent, we can free our structure | ||
169 | logmessages_free(&new_logmessage); | ||
170 | eina_counter_stop(counter, 1); | ||
171 | |||
172 | counterresult = eina_counter_dump(counter); | ||
173 | EINA_LOG_DOM_DBG(einadom_spy, "Message processing time :\n%s", counterresult); | ||
174 | free(counterresult); | ||
175 | eina_counter_free(counter); | ||
176 | } | ||
177 | else if( event == ECORE_FILE_EVENT_DELETED_SELF | ||
178 | || event == ECORE_FILE_EVENT_DELETED_DIRECTORY | ||
179 | || event == ECORE_FILE_EVENT_DELETED_FILE | ||
180 | ) | ||
181 | { | ||
182 | struct logfile *log = data, | ||
183 | *foundlog; | ||
184 | Eina_List *l; | ||
185 | EINA_LOG_DOM_DBG(einadom_spy, "Logfile %s has been deleted!", path); | ||
186 | |||
187 | // If this file was one of the files we used to monitor, | ||
188 | // We must delete it from our list | ||
189 | EINA_LIST_FOREACH(list_logfiles, l, foundlog) | ||
190 | { | ||
191 | if( !strcmp(foundlog->name, path) ) | ||
192 | { | ||
193 | list_logfiles = eina_list_remove(list_logfiles, log); | ||
194 | logfiles_del(&log); | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | else if( event == ECORE_FILE_EVENT_CREATED_FILE | ||
200 | || event == ECORE_FILE_EVENT_CREATED_DIRECTORY | ||
201 | ) | ||
202 | { | ||
203 | // A new log file has been made, we have to check if this file already is in our filelog | ||
204 | // And if a rule affects it. | ||
205 | // If so, we add it to our monitor | ||
206 | Eina_List *l; | ||
207 | struct rule *foundrule = NULL; | ||
208 | struct logfile *new_logfile = NULL; | ||
209 | fpos_t pos_tmp; | ||
210 | int ret, | ||
211 | got_it = 0; | ||
212 | |||
213 | EINA_LOG_DOM_DBG(einadom_spy, "Logfile %s has been created!", path); | ||
214 | |||
215 | // If we already monitor this file, then we ignore it | ||
216 | // Which might be a problem btw. This thing shouldnt happen | ||
217 | EINA_LIST_FOREACH(list_logfiles, l, new_logfile) | ||
218 | { | ||
219 | if( !strcmp(new_logfile->name, path) ) | ||
220 | return(ECORE_CALLBACK_RENEW); | ||
221 | } | ||
222 | |||
223 | EINA_LIST_FOREACH(list_rules, l, foundrule) | ||
224 | { | ||
225 | if( foundrule->filename ) | ||
226 | { | ||
227 | unsigned long long int filesize; | ||
228 | ret = fnmatch(foundrule->filename, path, FNM_NOESCAPE); | ||
229 | if( ret ) | ||
230 | continue; | ||
231 | |||
232 | // We get our cursor pos | ||
233 | logfiles_getbegin((char *)path, &pos_tmp); | ||
234 | logfiles_getsize((char *)path, &filesize); | ||
235 | logfiles_new(&new_logfile, (char *)path, pos_tmp, filesize); | ||
236 | |||
237 | logfiles_add(new_logfile); | ||
238 | efm = ecore_file_monitor_add(path, | ||
239 | (Ecore_File_Monitor_Cb)spy_event, | ||
240 | (void *)new_logfile); | ||
241 | |||
242 | got_it = 1; | ||
243 | break; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | if( got_it ) | ||
248 | { | ||
249 | // We must take attention to the fact that the file might | ||
250 | // Have been truncated | ||
251 | spy_extract_new_lines(new_logfile->name, new_logfile->cursor, &new_logfile->cursor, message); | ||
252 | |||
253 | // If nothing has been read, then file has been trunc and is empty | ||
254 | // So we do nothing | ||
255 | if( message[0] == 0 ) | ||
256 | return(ECORE_CALLBACK_RENEW); | ||
257 | |||
258 | logmessages_new(&new_logmessage, message, new_logfile->name); | ||
259 | rules_filtermessage(new_logmessage); | ||
260 | |||
261 | // Now we only have to send this filtered message to ES | ||
262 | if( !new_logmessage->todel ) | ||
263 | send_logmessage(new_logmessage); | ||
264 | |||
265 | // Message is sent, we can free our structure | ||
266 | logmessages_free(&new_logmessage); | ||
267 | } | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | EINA_LOG_DOM_DBG(einadom_spy, "WTF event on %s !", path); | ||
272 | |||
273 | } | ||
274 | return(ECORE_CALLBACK_RENEW); | ||
275 | } | ||
276 | |||
277 | |||
278 | |||
279 | /** | ||
280 | * @brief Gets the new log message that has been inserted. This function kind of sucks and has to | ||
281 | * be improved to really extract all the messages and send them to a callback that will | ||
282 | * process them intead of taking only one (which can cause a problem if we don't get | ||
283 | * one inotify per message logged). | ||
284 | * | ||
285 | * @param filename (char *) File that raised an event and should be read | ||
286 | * @param pos_cur (fpos_t) current cursor position for this file | ||
287 | * @param pos_new (fpos_t *) New position of the cursor after extracting the new message | ||
288 | * @param message (char *) message extracted from the logfile | ||
289 | * | ||
290 | * @return 0 or -1 if there is an error | ||
291 | */ | ||
292 | int spy_extract_new_lines(char *filename, fpos_t pos_cur, fpos_t *pos_new, char *message) | ||
293 | { | ||
294 | FILE *fp; | ||
295 | int ret; | ||
296 | fpos_t pos_begin; | ||
297 | |||
298 | fp = fopen(filename, "r"); | ||
299 | if( !fp ) | ||
300 | { | ||
301 | EINA_LOG_DOM_ERR(einadom_spy, "We haven't been able to open %s : %s", filename, strerror(errno)); | ||
302 | return(-1); | ||
303 | } | ||
304 | |||
305 | fgetpos(fp, &pos_begin); | ||
306 | |||
307 | |||
308 | // If we can't set cursor, file has been truncated! | ||
309 | ret = fsetpos(fp, &pos_cur); | ||
310 | if( ret ) | ||
311 | { | ||
312 | fsetpos(fp, &pos_begin); | ||
313 | *pos_new = pos_begin; | ||
314 | } | ||
315 | else *pos_new = pos_cur; | ||
316 | |||
317 | // This while is only here to avoid empty lines | ||
318 | while( 1 ) | ||
319 | { | ||
320 | ret = fscanf(fp,"%4096[^\n]\n", message); | ||
321 | |||
322 | if( ret == EOF ) | ||
323 | break; | ||
324 | |||
325 | // Didnt read anything | ||
326 | if( ret == 0) | ||
327 | { | ||
328 | char tmp[2]; | ||
329 | EINA_LOG_DOM_DBG(einadom_spy, "Empty line hack"); | ||
330 | ret = fread(tmp, 1, 1, fp); | ||
331 | if( ret != 1 ) | ||
332 | EINA_LOG_DOM_DBG(einadom_spy, "WTF?!"); | ||
333 | continue; | ||
334 | } | ||
335 | if( ret != 1 ) | ||
336 | { | ||
337 | fgetpos(fp, pos_new); | ||
338 | break; | ||
339 | } | ||
340 | else | ||
341 | fgetpos(fp, pos_new); | ||
342 | |||
343 | // We have a message to log | ||
344 | break; | ||
345 | } | ||
346 | |||
347 | fclose(fp); | ||
348 | return(0); | ||
349 | } | ||
diff --git a/src/bin/utils.c b/src/bin/utils.c deleted file mode 100644 index a9a9d4a..0000000 --- a/src/bin/utils.c +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2013 Guillaume Friloux <kuri@efl.so> | ||
3 | * | ||
4 | * This program is free software: you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation, either version 3 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "smman.h" | ||
20 | #include <time.h> | ||
21 | #include <stdio.h> | ||
22 | |||
23 | /** | ||
24 | * @brief Gets us the current date, in the same format as logstash. | ||
25 | * | ||
26 | * @return Pointer to the date's string, or NULL if an error | ||
27 | * occured. | ||
28 | */ | ||
29 | char * | ||
30 | utils_date(void) | ||
31 | { | ||
32 | char *s; | ||
33 | time_t temps; | ||
34 | struct tm temp; | ||
35 | |||
36 | temps = time(NULL); | ||
37 | if (!localtime_r(&temps,&temp)) | ||
38 | return NULL; | ||
39 | |||
40 | s = calloc(1, 28); | ||
41 | EINA_SAFETY_ON_NULL_RETURN_VAL(s, NULL); | ||
42 | |||
43 | sprintf(s,"%04d-%02d-%02dT%02d:%02d:%02d.000000Z", | ||
44 | (temp.tm_year)+1900,(temp.tm_mon)+1,temp.tm_mday, | ||
45 | temp.tm_hour,temp.tm_min,temp.tm_sec); | ||
46 | return s; | ||
47 | } | ||