1 /*
2  * s3fs - FUSE-based file system backed by Amazon S3
3  *
4  * Copyright(C) 2007 Randy Rizun <rrizun@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 
21 #ifndef S3FS_LOGGER_H_
22 #define S3FS_LOGGER_H_
23 
24 #include <cstdio>
25 #include <syslog.h>
26 #include <sys/time.h>
27 
28 #ifdef CLOCK_MONOTONIC_COARSE
29 #define S3FS_CLOCK_MONOTONIC    CLOCK_MONOTONIC_COARSE
30 #else
31 // case of OSX
32 #define S3FS_CLOCK_MONOTONIC    CLOCK_MONOTONIC
33 #endif
34 
35 //-------------------------------------------------------------------
36 // S3fsLog class
37 //-------------------------------------------------------------------
38 class S3fsLog
39 {
40     public:
41         enum s3fs_log_level{
42             LEVEL_CRIT = 0,          // LEVEL_CRIT
43             LEVEL_ERR  = 1,          // LEVEL_ERR
44             LEVEL_WARN = 3,          // LEVEL_WARNING
45             LEVEL_INFO = 7,          // LEVEL_INFO
46             LEVEL_DBG  = 15          // LEVEL_DEBUG
47         };
48 
49     protected:
50         static const int         NEST_MAX = 4;
51         static const char* const nest_spaces[NEST_MAX];
52         static const char        LOGFILEENV[];
53         static const char        MSGTIMESTAMP[];
54 
55         static S3fsLog*       pSingleton;
56         static s3fs_log_level debug_level;
57         static FILE*          logfp;
58         static std::string*   plogfile;
59         static bool           time_stamp;
60 
61     protected:
62         bool LowLoadEnv();
63         bool LowSetLogfile(const char* pfile);
64         s3fs_log_level LowSetLogLevel(s3fs_log_level level);
65         s3fs_log_level LowBumpupLogLevel();
66 
67     public:
68         static bool IsS3fsLogLevel(s3fs_log_level level);
69         static bool IsS3fsLogCrit()  { return IsS3fsLogLevel(LEVEL_CRIT); }
70         static bool IsS3fsLogErr()   { return IsS3fsLogLevel(LEVEL_ERR);  }
71         static bool IsS3fsLogWarn()  { return IsS3fsLogLevel(LEVEL_WARN); }
72         static bool IsS3fsLogInfo()  { return IsS3fsLogLevel(LEVEL_INFO); }
73         static bool IsS3fsLogDbg()   { return IsS3fsLogLevel(LEVEL_DBG);  }
74 
75         static int GetSyslogLevel(s3fs_log_level level)
76         {
77             return ( LEVEL_DBG  == (level & LEVEL_DBG) ? LOG_DEBUG   :
78                      LEVEL_INFO == (level & LEVEL_DBG) ? LOG_INFO    :
79                      LEVEL_WARN == (level & LEVEL_DBG) ? LOG_WARNING :
80                      LEVEL_ERR  == (level & LEVEL_DBG) ? LOG_ERR     : LOG_CRIT );
81         }
82 
83         static std::string GetCurrentTime();
84 
85         static const char* GetLevelString(s3fs_log_level level)
86         {
87             return ( LEVEL_DBG  == (level & LEVEL_DBG) ? "[DBG] " :
88                      LEVEL_INFO == (level & LEVEL_DBG) ? "[INF] " :
89                      LEVEL_WARN == (level & LEVEL_DBG) ? "[WAN] " :
90                      LEVEL_ERR  == (level & LEVEL_DBG) ? "[ERR] " : "[CRT] " );
91         }
92 
93         static const char* GetS3fsLogNest(int nest)
94         {
95             if(nest < NEST_MAX){
96                 return nest_spaces[nest];
97             }else{
98                 return nest_spaces[NEST_MAX - 1];
99             }
100         }
101 
102         static bool IsSetLogFile()
103         {
104             return (NULL != logfp);
105         }
106 
107         static FILE* GetOutputLogFile()
108         {
109             return (logfp ? logfp : stdout);
110         }
111 
112         static FILE* GetErrorLogFile()
113         {
114             return (logfp ? logfp : stderr);
115         }
116 
117         static void SeekEnd()
118         {
119             if(logfp){
120                 fseek(logfp, 0, SEEK_END);
121             }
122         }
123 
124         static void Flush()
125         {
126             if(logfp){
127                 fflush(logfp);
128             }
129         }
130 
131         static bool SetLogfile(const char* pfile);
132         static bool ReopenLogfile();
133         static s3fs_log_level SetLogLevel(s3fs_log_level level);
134         static s3fs_log_level BumpupLogLevel();
135         static bool SetTimeStamp(bool value);
136 
137         explicit S3fsLog();
138         ~S3fsLog();
139 };
140 
141 //-------------------------------------------------------------------
142 // Debug macros
143 //-------------------------------------------------------------------
144 #define S3FS_LOW_LOGPRN(level, fmt, ...) \
145         do{ \
146             if(S3fsLog::IsS3fsLogLevel(level)){ \
147                 if(foreground || S3fsLog::IsSetLogFile()){ \
148                     S3fsLog::SeekEnd(); \
149                     fprintf(S3fsLog::GetOutputLogFile(), "%s%s%s:%s(%d): " fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(level), __FILE__, __func__, __LINE__, __VA_ARGS__); \
150                     S3fsLog::Flush(); \
151                 }else{ \
152                     syslog(S3fsLog::GetSyslogLevel(level), "%s%s:%s(%d): " fmt "%s", instance_name.c_str(), __FILE__, __func__, __LINE__, __VA_ARGS__); \
153                 } \
154             } \
155         }while(0)
156 
157 #define S3FS_LOW_LOGPRN2(level, nest, fmt, ...) \
158         do{ \
159             if(S3fsLog::IsS3fsLogLevel(level)){ \
160                 if(foreground || S3fsLog::IsSetLogFile()){ \
161                     S3fsLog::SeekEnd(); \
162                     fprintf(S3fsLog::GetOutputLogFile(), "%s%s%s%s:%s(%d): " fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(level), S3fsLog::GetS3fsLogNest(nest), __FILE__, __func__, __LINE__, __VA_ARGS__); \
163                     S3fsLog::Flush(); \
164                 }else{ \
165                     syslog(S3fsLog::GetSyslogLevel(level), "%s%s" fmt "%s", instance_name.c_str(), S3fsLog::GetS3fsLogNest(nest), __VA_ARGS__); \
166                 } \
167             } \
168         }while(0)
169 
170 #define S3FS_LOW_CURLDBG(fmt, ...) \
171         do{ \
172             if(foreground || S3fsLog::IsSetLogFile()){ \
173                 S3fsLog::SeekEnd(); \
174                 fprintf(S3fsLog::GetOutputLogFile(), "%s[CURL DBG] " fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), __VA_ARGS__); \
175                 S3fsLog::Flush(); \
176             }else{ \
177                 syslog(S3fsLog::GetSyslogLevel(S3fsLog::LEVEL_CRIT), "%s" fmt "%s", instance_name.c_str(), __VA_ARGS__); \
178             } \
179         }while(0)
180 
181 #define S3FS_LOW_LOGPRN_EXIT(fmt, ...) \
182         do{ \
183             if(foreground || S3fsLog::IsSetLogFile()){ \
184                 S3fsLog::SeekEnd(); \
185                 fprintf(S3fsLog::GetErrorLogFile(), "s3fs: " fmt "%s\n", __VA_ARGS__); \
186                 S3fsLog::Flush(); \
187             }else{ \
188                 fprintf(S3fsLog::GetErrorLogFile(), "s3fs: " fmt "%s\n", __VA_ARGS__); \
189                 syslog(S3fsLog::GetSyslogLevel(S3fsLog::LEVEL_CRIT), "%ss3fs: " fmt "%s", instance_name.c_str(), __VA_ARGS__); \
190             } \
191         }while(0)
192 
193 // Special macro for init message
194 #define S3FS_PRN_INIT_INFO(fmt, ...) \
195         do{ \
196             if(foreground || S3fsLog::IsSetLogFile()){ \
197                 S3fsLog::SeekEnd(); \
198                 fprintf(S3fsLog::GetOutputLogFile(), "%s%s%s%s:%s(%d): " fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(S3fsLog::LEVEL_INFO), S3fsLog::GetS3fsLogNest(0), __FILE__, __func__, __LINE__, __VA_ARGS__, ""); \
199                 S3fsLog::Flush(); \
200             }else{ \
201                 syslog(S3fsLog::GetSyslogLevel(S3fsLog::LEVEL_INFO), "%s%s" fmt "%s", instance_name.c_str(), S3fsLog::GetS3fsLogNest(0), __VA_ARGS__, ""); \
202             } \
203         }while(0)
204 
205 #define S3FS_PRN_LAUNCH_INFO(fmt, ...) \
206         do{ \
207             if(foreground || S3fsLog::IsSetLogFile()){ \
208                 S3fsLog::SeekEnd(); \
209                 fprintf(S3fsLog::GetOutputLogFile(), "%s%s" fmt "%s\n", S3fsLog::GetCurrentTime().c_str(), S3fsLog::GetLevelString(S3fsLog::LEVEL_INFO), __VA_ARGS__, ""); \
210                 S3fsLog::Flush(); \
211             }else{ \
212                 syslog(S3fsLog::GetSyslogLevel(S3fsLog::LEVEL_INFO), "%s" fmt "%s", instance_name.c_str(), __VA_ARGS__, ""); \
213             } \
214         }while(0)
215 
216 // Special macro for checking cache files
217 #define S3FS_LOW_CACHE(fp, fmt, ...) \
218         do{ \
219             if(foreground || S3fsLog::IsSetLogFile()){ \
220                 S3fsLog::SeekEnd(); \
221                 fprintf(fp, fmt "%s\n", __VA_ARGS__); \
222                 S3fsLog::Flush(); \
223             }else{ \
224                 syslog(S3fsLog::GetSyslogLevel(S3fsLog::LEVEL_INFO), "%s: " fmt "%s", instance_name.c_str(), __VA_ARGS__); \
225             } \
226         }while(0)
227 
228 // [NOTE]
229 // small trick for VA_ARGS
230 //
231 #define S3FS_PRN_EXIT(fmt, ...)   S3FS_LOW_LOGPRN_EXIT(fmt, ##__VA_ARGS__, "")
232 #define S3FS_PRN_CRIT(fmt, ...)   S3FS_LOW_LOGPRN(S3fsLog::LEVEL_CRIT, fmt, ##__VA_ARGS__, "")
233 #define S3FS_PRN_ERR(fmt, ...)    S3FS_LOW_LOGPRN(S3fsLog::LEVEL_ERR,  fmt, ##__VA_ARGS__, "")
234 #define S3FS_PRN_WARN(fmt, ...)   S3FS_LOW_LOGPRN(S3fsLog::LEVEL_WARN, fmt, ##__VA_ARGS__, "")
235 #define S3FS_PRN_DBG(fmt, ...)    S3FS_LOW_LOGPRN(S3fsLog::LEVEL_DBG,  fmt, ##__VA_ARGS__, "")
236 #define S3FS_PRN_INFO(fmt, ...)   S3FS_LOW_LOGPRN2(S3fsLog::LEVEL_INFO, 0, fmt, ##__VA_ARGS__, "")
237 #define S3FS_PRN_INFO1(fmt, ...)  S3FS_LOW_LOGPRN2(S3fsLog::LEVEL_INFO, 1, fmt, ##__VA_ARGS__, "")
238 #define S3FS_PRN_INFO2(fmt, ...)  S3FS_LOW_LOGPRN2(S3fsLog::LEVEL_INFO, 2, fmt, ##__VA_ARGS__, "")
239 #define S3FS_PRN_INFO3(fmt, ...)  S3FS_LOW_LOGPRN2(S3fsLog::LEVEL_INFO, 3, fmt, ##__VA_ARGS__, "")
240 #define S3FS_PRN_CURL(fmt, ...)   S3FS_LOW_CURLDBG(fmt, ##__VA_ARGS__, "")
241 #define S3FS_PRN_CACHE(fp, ...)   S3FS_LOW_CACHE(fp, ##__VA_ARGS__, "")
242 
243 #endif // S3FS_LOGGER_H_
244 
245 /*
246 * Local variables:
247 * tab-width: 4
248 * c-basic-offset: 4
249 * End:
250 * vim600: expandtab sw=4 ts=4 fdm=marker
251 * vim<600: expandtab sw=4 ts=4
252 */
253