1 #include <log4cpp/Category.hh>
2 #include <log4cpp/PropertyConfigurator.hh>
3 #include <log4cpp/DailyRollingFileAppender.hh>
4 #include <log4cpp/PatternLayout.hh>
5 #include <log4cpp/OstreamAppender.hh>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <iostream>
10 #include <ctime>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <memory>
14 #include <cstring>
15
16 #ifdef LOG4CPP_HAVE_IO_H
17 # include <io.h>
18 #endif
19 #ifdef LOG4CPP_HAVE_UNISTD_H
20 # include <unistd.h>
21 #endif
22
23 #ifndef WIN32 // only available on Win32
24 #include <dirent.h>
25 #else
26 #include <direct.h>
27 #endif
28
29 #ifdef WIN32
30 #pragma comment(lib, "Ws2_32.lib")
31 #endif
32
33 using namespace log4cpp;
34 using namespace std;
35 static const char* const test_message = "message";
36 static const char* const daily_file_prefix = "dailyrolling_file.log";
37 static const char* const nestedDir = "nesteddir";
38 #ifndef WIN32
39 #define PATHDELIMITER "/"
40 #else
41 #define PATHDELIMITER "\\"
42 #endif
43 const char* const nesteddirname = "nesteddir"PATHDELIMITER;
44
45
46 class DailyRollingTest {
47 DailyRollingFileAppender* dailyApp, *nestedDirDailyApp;
48 public:
remove_impl(const char * filename)49 bool remove_impl(const char* filename)
50 {
51 int res = remove(filename);
52
53 if (res != 0 && errno != ENOENT)
54 cout << "Can't remove file '" << filename << "'.\n";
55
56 return res == 0 || (res != 0 && errno == ENOENT);
57 }
58
remove_files()59 bool remove_files()
60 {
61 // if (!remove_impl(daily_file_prefix))
62 // return false;
63
64 return true;
65 }
66
setup()67 bool setup()
68 {
69 if (!remove_files())
70 return false;
71
72 Category& root = Category::getRoot();
73 dailyApp = new DailyRollingFileAppender("daily-rolling-appender", daily_file_prefix, 1);
74 nestedDirDailyApp = new DailyRollingFileAppender("nesteddir-daily-rolling-appender", std::string(nesteddirname).append(daily_file_prefix), 1);
75 root.addAppender(dailyApp);
76 root.addAppender(nestedDirDailyApp);
77 root.setPriority(Priority::DEBUG);
78
79 return true;
80 }
81
make_log_files()82 void make_log_files()
83 {
84 Category::getRoot().debugStream() << test_message << 1;
85 Category::getRoot().debugStream() << test_message << 2;
86 Category::getRoot().debugStream() << test_message << 3;
87 Category::getRoot().debugStream() << "The message before rolling over attempt";
88 dailyApp->rollOver();
89 nestedDirDailyApp->rollOver();
90 Category::getRoot().debugStream() << "The message after rolling over attempt";
91 Category::getRoot().debugStream() << test_message << 4;
92 Category::getRoot().debugStream() << test_message << 5;
93 }
94
exists(const char * filename)95 bool exists(const char* filename)
96 {
97 FILE* f = fopen(filename, "r");
98 if (f == NULL)
99 {
100 cout << "File '" << filename << "' doesn't exists.\n";
101 return false;
102 }
103
104 fclose(f);
105
106 return true;
107 }
108
check_log_files()109 bool check_log_files()
110 {
111 bool result = exists(daily_file_prefix);
112
113 Category::shutdown();
114 return result && remove_files();
115 }
116 };
117
testOnlyDailyRollingFileAppender()118 int testOnlyDailyRollingFileAppender() {
119 DailyRollingTest dailyTest;
120 if (!dailyTest.setup())
121 {
122 cout << "Setup has failed. Check for permissions on files " << daily_file_prefix << "*'.\n";
123 return -1;
124 }
125
126 dailyTest.make_log_files();
127
128 if (dailyTest.check_log_files())
129 return 0;
130 else
131 return -1;
132 }
133
testConfigDailyRollingFileAppender()134 int testConfigDailyRollingFileAppender()
135 {
136 /* looking for the init file in $srcdir is a requirement of
137 automake's distcheck target.
138 */
139 const char* srcdir = getenv("srcdir");
140 std::string initFileName;
141 try {
142 #if defined(WIN32)
143 initFileName = "./testConfig.log4cpp.dailyroll.nt.properties";
144 #else
145 initFileName = "./testConfig.log4cpp.dailyroll.properties";
146 #endif
147 if (srcdir != NULL) {
148 initFileName = std::string(srcdir) + PATHDELIMITER + initFileName;
149 }
150
151 log4cpp::PropertyConfigurator::configure(initFileName);
152 } catch(log4cpp::ConfigureFailure& f) {
153 std::cout << "Configure Problem " << f.what() << "($srcdir=" << ((srcdir != NULL)?srcdir:"NULL") << ")" << std::endl;
154 return -1;
155 }
156
157 log4cpp::Category& root = log4cpp::Category::getRoot();
158
159 log4cpp::Category& sub1 =
160 log4cpp::Category::getInstance(std::string("sub1"));
161
162 root.error("root error");
163 root.warn("root warn");
164 sub1.error("sub1 error");
165 sub1.warn("sub1 warn");
166
167 log4cpp::Category::shutdown();
168 return 0;
169 }
170
171 // Note: this test changes system time. Run it only manually
172 namespace OnlyManualTesting {
173
174 const char* absolutePathCategoryName = "absolutePathCategory";
175 const int maxDaysToKeep = 3;
176
177 #if defined(WIN32)
178 const char *logFilename = "C:\\Temp\\log4cpp\\dailyrolling_abs_path_file.log";
179 const char *logPathname = "C:\\Temp\\log4cpp";
180 #else
181 const char *logFilename = "/var/log/log4cpp/dailyrolling_abs_path_file.log";
182 const char *logPathname = "/var/log/log4cpp";
183 #endif
184
setupManualEntryLog()185 void setupManualEntryLog() {
186 #if defined(WIN32)
187 if (access(logPathname, 0) != 0) {
188 mkdir(logPathname);
189 }
190 #else
191 if (access(logPathname, F_OK) != 0) {
192 mkdir(logPathname, 644);
193 }
194 #endif
195
196 log4cpp::PatternLayout *ostreamLayout = new log4cpp::PatternLayout();
197 ostreamLayout->setConversionPattern("%d: %p %c %x: %m %n");
198 log4cpp::Appender *ostreamAppender = new log4cpp::OstreamAppender("ostreamAppender", &std::cout);
199 ostreamAppender->setLayout(ostreamLayout);
200
201 log4cpp::PatternLayout *fileLayout = new log4cpp::PatternLayout();
202 fileLayout->setConversionPattern("%d: %p %c %x: %m %n");
203 log4cpp::Appender *fileAppender = new log4cpp::DailyRollingFileAppender("fileAppender", logFilename, maxDaysToKeep);
204 fileAppender->setLayout(fileLayout);
205
206 log4cpp::Category& absolutePathCategory =
207 log4cpp::Category::getInstance(std::string(absolutePathCategoryName));
208 absolutePathCategory.setAdditivity(false);
209
210 absolutePathCategory.addAppender(ostreamAppender);
211 absolutePathCategory.addAppender(fileAppender);
212 absolutePathCategory.setPriority(log4cpp::Priority::DEBUG);
213 }
214
215 int checkThatNoMoreThanNLogFilesPresent(const std::string _fileName, int n);
216
jumpToFuture(int seconds)217 int jumpToFuture(int seconds) {
218
219 #if defined(WIN32)
220 SYSTEMTIME now;
221 GetSystemTime(&now);
222 now.wDay += seconds / (24*60*60);
223 now.wSecond += 1;
224 if (SetSystemTime(&now) == 0) {
225 std::cerr << "Can not change system time. Probably not today... Try running as admin? Err: " << GetLastError() << std::endl;
226 return -1;
227 }
228 #else
229 time_t now;
230 if (time(&now) == -1)
231 return -1;
232
233 now += seconds;
234
235 if (stime(&now) == -1) {
236 std::cerr << "Can not set date. Need admin privileges?" << std::endl;
237 return -1;
238 }
239 #endif
240 return 0;
241 }
242
makeManualEntryLog()243 int makeManualEntryLog()
244 {
245 const int totalLinesCount = 14, linesPerDay=3, jumpPeriod=24*60*60 + 1;
246 int i = 0, future = 0;
247
248 log4cpp::Category& absolutePathCategory =
249 log4cpp::Category::getInstance(std::string(absolutePathCategoryName));
250
251 // 1. update system time (eg: use 'date' command on Linux) manually when test program is running here (at least 4 times)
252 absolutePathCategory.debugStream() << "debug line " << i;
253 while (++i <= totalLinesCount) {
254 if (i % linesPerDay == 0) {
255 if (jumpToFuture(jumpPeriod) == -1)
256 return -1;
257 future += jumpPeriod;
258 }
259 absolutePathCategory.debugStream() << "debug line " << i;
260 }
261
262 if (jumpToFuture(0-future) == -1)
263 return -1;
264
265 // 2. check the number of files in /var/log/log4cpp ( <= maxDaysToKeep) (+1 to allow consequent runs of test)
266 if (checkThatNoMoreThanNLogFilesPresent(std::string(logFilename), maxDaysToKeep + 1) == -1)
267 return -1;
268
269 return 0;
270 }
271
272 // Note: this test changes system time. Run it only manually
checkThatNoMoreThanNLogFilesPresent(const std::string _fileName,int n)273 int checkThatNoMoreThanNLogFilesPresent(const std::string _fileName, int n) {
274 // iterate over files around log file and count files with same prefix
275 const std::string::size_type last_delimiter = _fileName.rfind(PATHDELIMITER);
276 const std::string dirname((last_delimiter == std::string::npos)? "." : _fileName.substr(0, last_delimiter));
277 const std::string filname((last_delimiter == std::string::npos)? _fileName : _fileName.substr(last_delimiter+1, _fileName.size()-last_delimiter-1));
278 int logFilesCount(0);
279 #ifndef WIN32 // only available on Win32
280 struct dirent **entries;
281 int nentries = scandir(dirname.c_str(), &entries, 0, alphasort);
282 if (nentries < 0)
283 return -1;
284 for (int i = 0; i < nentries; i++) {
285 if (strstr(entries[i]->d_name, filname.c_str())) {
286 ++logFilesCount;
287 }
288 free(entries[i]);
289 }
290 free(entries);
291 #else
292 HANDLE hFind = INVALID_HANDLE_VALUE;
293 WIN32_FIND_DATA ffd;
294 const std::string pattern = _fileName + "*";
295
296 hFind = FindFirstFile(pattern.c_str(), &ffd);
297 if (hFind != INVALID_HANDLE_VALUE) {
298 do {
299 if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
300 ++logFilesCount;
301 }
302 } while (FindNextFile(hFind, &ffd) != 0);
303 FindClose(hFind);
304 hFind = INVALID_HANDLE_VALUE;
305 }
306 #endif
307 if (logFilesCount > n) {
308 std::cerr << "Too many log files in the dir " << dirname << ": " << logFilesCount << std::endl;
309 } else {
310 std::cout << "Daily log files in the dir " << dirname << ": " << logFilesCount << std::endl;
311 }
312
313 return (logFilesCount <= n) ? 0 : -1;
314 }
315
testDailyRollingFileAppenderChangeDateManualOnly()316 int testDailyRollingFileAppenderChangeDateManualOnly() {
317 setupManualEntryLog();
318 return makeManualEntryLog();
319 }
320 }
321
main()322 int main()
323 {
324 int res = testOnlyDailyRollingFileAppender();
325 if (!res)
326 res = testConfigDailyRollingFileAppender();
327
328 // Note: this test changes system time. Run it only manually
329 // if (!res)
330 // res = OnlyManualTesting::testDailyRollingFileAppenderChangeDateManualOnly();
331
332 return res;
333 }
334