Imported Upstream version 0.8~alpha1
[platform/upstream/syncevolution.git] / src / client-api / src / c++ / posix / base / Log.cpp
1 /*
2  * Funambol is a mobile platform developed by Funambol, Inc.
3  * Copyright (C) 2003 - 2007 Funambol, Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Affero General Public License version 3 as published by
7  * the Free Software Foundation with the addition of the following permission
8  * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
9  * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
10  * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program; if not, see http://www.gnu.org/licenses or write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20  * MA 02110-1301 USA.
21  *
22  * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
23  * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
24  *
25  * The interactive user interfaces in modified source and object code versions
26  * of this program must display Appropriate Legal Notices, as required under
27  * Section 5 of the GNU Affero General Public License version 3.
28  *
29  * In accordance with Section 7(b) of the GNU Affero General Public License
30  * version 3, these Appropriate Legal Notices must retain the display of the
31  * "Powered by Funambol" logo. If the display of the logo is not reasonably
32  * feasible for technical reasons, the Appropriate Legal Notices must display
33  * the words "Powered by Funambol".
34  */
35
36
37 #include "base/globalsdef.h"
38 #include "base/posixlog.h"
39 #include "base/fscapi.h"
40 #include "base/util/utils.h"
41
42 #include <unistd.h>
43
44 USE_NAMESPACE
45
46 //char logmsg[512];
47
48 POSIXLog::POSIXLog() :
49     logFile(NULL),
50     logFileStdout(false),
51     logName(LOG_NAME),
52     logRedirectStderr(false),
53     fderr(-1),
54     prefix("")
55 {
56 }
57
58 void POSIXLog::setLogPath(const char*  configLogPath) {
59     logPath.sprintf("%s/", configLogPath ? configLogPath : "./");
60 }
61
62 void POSIXLog::setLogName(const char*  configLogName) {
63     logName.sprintf("%s", configLogName ? configLogName : LOG_NAME);
64 }
65
66 void POSIXLog::setLogFile(const char *path, const char* name, bool redirectStderr) {
67     if (path != logPath.c_str()) {
68         setLogPath(path);
69     }
70     if (name != logName.c_str()) {
71         setLogName(name);
72     }
73     logRedirectStderr = redirectStderr;
74
75     if (logFile != NULL) {
76         fclose(logFile);
77         logFile = NULL;
78     }
79     logFileStdout = false;
80
81     if (!strcmp(name, "-")) {
82         // write to stdout
83         logFileStdout = true;
84     } else if (path) {
85         char *filename = new char[strlen(path) + strlen(name) + 3];
86
87         sprintf(filename, "%s/%s", path, name);
88         logFile = fopen(filename, "a+" );
89         delete [] filename;
90     } else {
91         logFile = fopen(name, "a+" );
92     }
93
94     if (logFile) {
95         char buffer[256];
96         struct tm tm;
97         time_t t = time(NULL);
98
99         // We log UTC at the start of each line.
100         // Log the current user's time offset.
101         localtime_r(&t, &tm);
102         strftime(buffer, sizeof(buffer),
103                  "local timezone: %Z = GMT %z",
104                  &tm);
105         developer("%s", buffer);
106         asctime_r(&tm, buffer);
107         developer("local time: %s", buffer);
108         gmtime_r(&t, &tm);
109         asctime_r(&tm, buffer);
110         developer("world time: %s", buffer);
111     }
112
113     if (redirectStderr && logFile) {
114         if (fderr == -1) {
115             // remember original stderr
116             fderr = dup(2);
117         }
118         // overwrite stderr with log file fd,
119         // closing the current stderr if necessary
120         dup2(fileno(logFile), 2);
121     } else {
122         if (fderr != -1) {
123             // restore original stderr
124             dup2(fderr, 2);
125         }
126     }
127 }
128
129 POSIXLog::~POSIXLog() {
130     if (logFile != NULL) {
131         fclose(logFile);
132     }
133 }
134
135 void POSIXLog::error(const char*  msg, ...) {
136     va_list argList;
137     va_start (argList, msg);
138     printMessage(LOG_LEVEL_NONE, LOG_ERROR, msg, argList);
139     va_end(argList);
140 }
141
142 void POSIXLog::info(const char*  msg, ...) {
143     if (isLoggable(LOG_LEVEL_INFO)) {
144         va_list argList;
145         va_start (argList, msg);
146         printMessage(LOG_LEVEL_INFO, LOG_INFO, msg, argList);
147         va_end(argList);
148     }
149 }
150
151 void POSIXLog::developer(const char*  msg, ...) {
152     if (isLoggable(LOG_LEVEL_INFO)) {
153         va_list argList;
154         va_start (argList, msg);
155         printMessage(LOG_LEVEL_DEBUG, LOG_DEBUG, msg, argList);
156         va_end(argList);
157     }
158 }
159
160 void POSIXLog::debug(const char*  msg, ...) {
161     if (isLoggable(LOG_LEVEL_DEBUG)) {
162         va_list argList;
163         va_start (argList, msg);
164         printMessage(LOG_LEVEL_DEBUG, LOG_DEBUG, msg, argList);
165         va_end(argList);
166     }
167 }
168
169 void POSIXLog::printLine(bool firstLine,
170                          time_t time,
171                          const char *fullTime,
172                          const char *shortTime,
173                          const char *utcTime,
174                          LogLevel level,
175                          const char *levelPrefix,
176                          const char *line)
177 {
178     FILE *out = getLogFile();
179     if (!out) {
180         out = stdout;
181     }
182     if (firstLine) {
183         fprintf(out, "%s [%s] %s%s\n",
184                 logFile ? utcTime : shortTime,
185                 levelPrefix,
186                 getPrefix().c_str(),
187                 line);
188     } else {
189         fprintf(out, "[%s] %s%s\n",
190                 levelPrefix,
191                 getPrefix().c_str(),
192                 line);
193     }
194     fflush(out);
195 }
196
197 void POSIXLog::printMessage(LogLevel level, const char* levelPrefix, const char* msg, va_list argList) {
198     time_t t = time(NULL);
199     struct tm sys_time;
200     struct tm utc_time;
201     char fullTime[64], shortTime[32];
202     char utcTime[32];
203
204     localtime_r(&t, &sys_time);
205     gmtime_r(&t, &utc_time);
206
207     strftime(fullTime, sizeof(fullTime), "%F %T GMT %z", &sys_time);
208     strftime(shortTime, sizeof(shortTime), "%T", &sys_time);
209     sprintf(utcTime, "%02d:%02d:%02d GMT",
210             utc_time.tm_hour,
211             utc_time.tm_min,
212             utc_time.tm_sec);
213
214     if (!logFileStdout && !logFile) {
215         reset();
216     }
217
218     StringBuffer buffer;
219     buffer.vsprintf(msg, argList);
220     const char *start = buffer.c_str();
221     const char *eol = strchr(start, '\n');
222     bool firstLine = true;
223     while (eol) {
224         /* hack: StringBuffer does not really allow write access, but do it anyway */
225         *(char *)eol = 0;
226         printLine(firstLine,
227                   t,
228                   fullTime,
229                   shortTime,
230                   utcTime,
231                   level,
232                   levelPrefix,
233                   start);
234         firstLine = false;
235         *(char *)eol = '\n';
236         start = eol + 1;
237         eol = strchr(start, '\n');
238     }
239     printLine(firstLine,
240               t,
241               fullTime,
242               shortTime,
243               utcTime,
244               level,
245               levelPrefix,
246               start);
247 }
248
249
250 void POSIXLog::reset(const char*  title) {
251     setLogFile(logPath, logName, logRedirectStderr);
252
253     if (logFile) {
254         ftruncate(fileno(logFile), 0);
255     }
256 }
257
258
259 size_t POSIXLog::getLogSize() {
260     size_t ret = 0;
261
262     if (logFile) {
263         ret = fgetsize(logFile);
264         fclose(logFile);
265     }
266     return ret;
267 }
268
269
270 Log *Log::logger;
271
272 Log &Log::instance() {
273     if (!logger) {
274         logger = new POSIXLog();
275     }
276     return *logger;
277 }
278