Merge working tree with build tree.
[awesomized/libmemcached] / util / log.hpp
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * libtest
4 *
5 * Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #pragma once
23
24 #include <cerrno>
25 #include <cstdarg>
26 #include <cstdio>
27 #include <fcntl.h>
28 #include <iostream>
29 #include <string>
30 #include <syslog.h>
31
32 #define UTIL_MAX_ERROR_SIZE 2048
33
34 namespace datadifferential {
35 namespace util {
36
37 /** Verbosity levels.
38 */
39 enum verbose_t
40 {
41 // Logging this will cause shutdown
42 VERBOSE_FATAL= LOG_EMERG, // syslog:LOG_EMERG
43
44 VERBOSE_ALERT= LOG_ALERT, // syslog:LOG_ALERT
45 VERBOSE_CRITICAL= LOG_CRIT, // syslog:LOG_CRIT
46
47 VERBOSE_ERROR= LOG_ERR, // syslog:LOG_ERR
48
49 VERBOSE_WARN= LOG_WARNING, // syslog:LOG_WARNING
50
51 VERBOSE_NOTICE= LOG_NOTICE, // syslog:LOG_NOTICE
52
53 VERBOSE_INFO= LOG_INFO, // syslog:LOG_INFO
54
55 VERBOSE_DEBUG= LOG_DEBUG // syslog:LOG_DEBUG
56 };
57
58
59 struct log_info_st
60 {
61 std::string name;
62 std::string filename;
63 int fd;
64 bool opt_syslog;
65 bool opt_file;
66 bool init_success;
67
68 log_info_st(const std::string& name_arg, const std::string &filename_arg, bool syslog_arg) :
69 name(name_arg),
70 filename(filename_arg),
71 fd(-1),
72 opt_syslog(syslog_arg),
73 opt_file(false),
74 init_success(false)
75 {
76 if (opt_syslog)
77 {
78 openlog(name.c_str(), LOG_PID | LOG_NDELAY, LOG_USER);
79 }
80
81 init();
82 }
83
84 void init()
85 {
86 if (filename.size())
87 {
88 if (filename.compare("stderr") == 0)
89 {
90 fd= STDERR_FILENO;
91 }
92 else
93 {
94 fd= open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
95 if (fd == -1)
96 {
97 if (opt_syslog)
98 {
99 char buffer[1024];
100 char *getcwd_ret= getcwd(buffer, sizeof(buffer));
101 syslog(LOG_ERR, "Could not open log file \"%.*s\", from \"%s\", open failed with (%s)",
102 int(filename.size()), filename.c_str(),
103 getcwd_ret,
104 strerror(errno));
105 }
106 std::cerr << "Could not open log file for writing, switching to stderr." << std::endl;
107
108 fd= STDERR_FILENO;
109 }
110 }
111
112 opt_file= true;
113 }
114
115 init_success= true;
116 }
117
118 bool initialized() const
119 {
120 return init_success;
121 }
122
123 int file() const
124 {
125 return fd;
126 }
127
128 void write(verbose_t verbose, const char *format, ...)
129 {
130 if (opt_file or opt_syslog)
131 {
132 va_list args;
133 va_start(args, format);
134 char mesg[BUFSIZ];
135 int mesg_length= vsnprintf(mesg, sizeof(mesg), format, args);
136 va_end(args);
137
138 if (opt_file)
139 {
140 char buffer[UTIL_MAX_ERROR_SIZE];
141 int buffer_length= snprintf(buffer, sizeof(buffer), "%7s %.*s\n", verbose_name(verbose), mesg_length, mesg);
142 if (::write(file(), buffer, buffer_length) == -1)
143 {
144 std::cerr << "Could not write to log file." << std::endl;
145 syslog(LOG_EMERG, "gearmand could not open log file %s, got error %s", filename.c_str(), strerror(errno));
146 }
147
148 }
149
150 if (opt_syslog)
151 {
152 syslog(int(verbose), "%7s %.*s", verbose_name(verbose), mesg_length, mesg);
153 }
154 }
155 }
156
157 ~log_info_st()
158 {
159 if (fd != -1 and fd != STDERR_FILENO)
160 {
161 close(fd);
162 }
163
164 if (opt_syslog)
165 {
166 closelog();
167 }
168 }
169
170 private:
171 const char *verbose_name(verbose_t verbose)
172 {
173 switch (verbose)
174 {
175 case VERBOSE_FATAL:
176 return "FATAL";
177
178 case VERBOSE_ALERT:
179 return "ALERT";
180
181 case VERBOSE_CRITICAL:
182 return "CRITICAL";
183
184 case VERBOSE_ERROR:
185 return "ERROR";
186
187 case VERBOSE_WARN:
188 return "WARNING";
189
190 case VERBOSE_NOTICE:
191 return "NOTICE";
192
193 case VERBOSE_INFO:
194 return "INFO";
195
196 case VERBOSE_DEBUG:
197 return "DEBUG";
198
199 default:
200 break;
201 }
202
203 return "UNKNOWN";
204 }
205 };
206
207 } // namespace util
208 } // namespace datadifferential