{GPL, other}: Relicense to MIT license.
[collectd.git] / src / logfile.c
1 /**
2  * collectd - src/logfile.c
3  * Copyright (C) 2007       Sebastian Harl
4  * Copyright (C) 2007,2008  Florian Forster
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *   Sebastian Harl <sh at tokkee.org>
26  *   Florian Forster <octo at collectd.org>
27  **/
28
29 #include "collectd.h"
30 #include "common.h"
31 #include "plugin.h"
32
33 #include <pthread.h>
34
35 #define DEFAULT_LOGFILE LOCALSTATEDIR"/log/collectd.log"
36
37 #if COLLECT_DEBUG
38 static int log_level = LOG_DEBUG;
39 #else
40 static int log_level = LOG_INFO;
41 #endif /* COLLECT_DEBUG */
42
43 static pthread_mutex_t file_lock = PTHREAD_MUTEX_INITIALIZER;
44
45 static char *log_file = NULL;
46 static int print_timestamp = 1;
47 static int print_severity = 0;
48
49 static const char *config_keys[] =
50 {
51         "LogLevel",
52         "File",
53         "Timestamp",
54         "PrintSeverity"
55 };
56 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
57
58 static int logfile_config (const char *key, const char *value)
59 {
60         if (0 == strcasecmp (key, "LogLevel")) {
61                 log_level = parse_log_severity(value);
62                 if (log_level < 0) {
63                         log_level = LOG_INFO;
64                         ERROR ("logfile: invalid loglevel [%s] defaulting to 'info'", value);
65                         return (1);
66                 }
67         }
68         else if (0 == strcasecmp (key, "File")) {
69                 sfree (log_file);
70                 log_file = strdup (value);
71         }
72         else if (0 == strcasecmp (key, "Timestamp")) {
73                 if (IS_FALSE (value))
74                         print_timestamp = 0;
75                 else
76                         print_timestamp = 1;
77         } else if (0 == strcasecmp(key, "PrintSeverity")) {
78                 if (IS_FALSE (value))
79                         print_severity = 0;
80                 else
81                         print_severity = 1;
82         }
83         else {
84                 return -1;
85         }
86         return 0;
87 } /* int logfile_config (const char *, const char *) */
88
89 static void logfile_print (const char *msg, int severity,
90                 cdtime_t timestamp_time)
91 {
92         FILE *fh;
93         _Bool do_close = 0;
94         struct tm timestamp_tm;
95         char timestamp_str[64];
96         char level_str[16] = "";
97
98         if (print_severity)
99         {
100                 switch (severity)
101                 {
102                 case LOG_ERR:
103                         snprintf(level_str, sizeof (level_str), "[error] ");
104                         break;  
105                 case LOG_WARNING:
106                         snprintf(level_str, sizeof (level_str), "[warning] ");
107                         break;
108                 case LOG_NOTICE:
109                         snprintf(level_str, sizeof (level_str), "[notice] ");
110                         break;  
111                 case LOG_INFO:
112                         snprintf(level_str, sizeof (level_str), "[info] ");
113                         break;  
114                 case LOG_DEBUG:
115                         snprintf(level_str, sizeof (level_str), "[debug] ");
116                         break;  
117                 default:
118                         break;
119                 }
120         }
121
122         if (print_timestamp)
123         {
124                 time_t tt = CDTIME_T_TO_TIME_T (timestamp_time);
125                 localtime_r (&tt, &timestamp_tm);
126
127                 strftime (timestamp_str, sizeof (timestamp_str), "%Y-%m-%d %H:%M:%S",
128                                 &timestamp_tm);
129                 timestamp_str[sizeof (timestamp_str) - 1] = '\0';
130         }
131
132         pthread_mutex_lock (&file_lock);
133
134         if (log_file == NULL)
135         {
136                 fh = fopen (DEFAULT_LOGFILE, "a");
137                 do_close = 1;
138         }
139         else if (strcasecmp (log_file, "stderr") == 0)
140                 fh = stderr;
141         else if (strcasecmp (log_file, "stdout") == 0)
142                 fh = stdout;
143         else
144         {
145                 fh = fopen (log_file, "a");
146                 do_close = 1;
147         }
148
149         if (fh == NULL)
150         {
151                         char errbuf[1024];
152                         fprintf (stderr, "logfile plugin: fopen (%s) failed: %s\n",
153                                         (log_file == NULL) ? DEFAULT_LOGFILE : log_file,
154                                         sstrerror (errno, errbuf, sizeof (errbuf)));
155         }
156         else
157         {
158                 if (print_timestamp)
159                         fprintf (fh, "[%s] %s%s\n", timestamp_str, level_str, msg);
160                 else
161                         fprintf (fh, "%s%s\n", level_str, msg);
162
163                 if (do_close) {
164                         fclose (fh);
165                 } else {
166                         fflush(fh);
167                 }
168         }
169
170         pthread_mutex_unlock (&file_lock);
171
172         return;
173 } /* void logfile_print */
174
175 static void logfile_log (int severity, const char *msg,
176                 user_data_t __attribute__((unused)) *user_data)
177 {
178         if (severity > log_level)
179                 return;
180
181         logfile_print (msg, severity, cdtime ());
182 } /* void logfile_log (int, const char *) */
183
184 static int logfile_notification (const notification_t *n,
185                 user_data_t __attribute__((unused)) *user_data)
186 {
187         char  buf[1024] = "";
188         char *buf_ptr = buf;
189         int   buf_len = sizeof (buf);
190         int status;
191
192         status = ssnprintf (buf_ptr, buf_len, "Notification: severity = %s",
193                         (n->severity == NOTIF_FAILURE) ? "FAILURE"
194                         : ((n->severity == NOTIF_WARNING) ? "WARNING"
195                                 : ((n->severity == NOTIF_OKAY) ? "OKAY" : "UNKNOWN")));
196         if (status > 0)
197         {
198                 buf_ptr += status;
199                 buf_len -= status;
200         }
201
202 #define APPEND(bufptr, buflen, key, value) \
203         if ((buflen > 0) && (strlen (value) > 0)) { \
204                 int status = ssnprintf (bufptr, buflen, ", %s = %s", key, value); \
205                 if (status > 0) { \
206                         bufptr += status; \
207                         buflen -= status; \
208                 } \
209         }
210         APPEND (buf_ptr, buf_len, "host", n->host);
211         APPEND (buf_ptr, buf_len, "plugin", n->plugin);
212         APPEND (buf_ptr, buf_len, "plugin_instance", n->plugin_instance);
213         APPEND (buf_ptr, buf_len, "type", n->type);
214         APPEND (buf_ptr, buf_len, "type_instance", n->type_instance);
215         APPEND (buf_ptr, buf_len, "message", n->message);
216
217         buf[sizeof (buf) - 1] = '\0';
218
219         logfile_print (buf, LOG_INFO,
220                         (n->time != 0) ? n->time : cdtime ());
221
222         return (0);
223 } /* int logfile_notification */
224
225 void module_register (void)
226 {
227         plugin_register_config ("logfile", logfile_config,
228                         config_keys, config_keys_num);
229         plugin_register_log ("logfile", logfile_log, /* user_data = */ NULL);
230         plugin_register_notification ("logfile", logfile_notification,
231                         /* user_data = */ NULL);
232 } /* void module_register (void) */
233
234 /* vim: set sw=4 ts=4 tw=78 noexpandtab : */
235