1 karl 1.43 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.13 //
|
3 karl 1.36 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.32 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.36 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.38 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.43 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.13 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
15 kumpf 1.18 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
18 mike 1.13 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
20 //
|
21 kumpf 1.18 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
22 mike 1.13 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
24 kumpf 1.18 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
27 mike 1.13 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include <iostream>
35 #include <fstream>
|
36 kumpf 1.23 #include <cstring>
|
37 mreddy 1.55 #include <Pegasus/Common/Logger.h>
|
38 marek 1.59 #include <Pegasus/Common/Tracer.h>
|
39 mreddy 1.55 #include <Pegasus/Common/System.h>
40 #include <Pegasus/Common/FileSystem.h>
|
41 kumpf 1.48 #include <Pegasus/Common/MessageLoader.h>
|
42 kumpf 1.54 #include <Pegasus/Common/Executor.h>
|
43 mreddy 1.55 #include <Pegasus/Common/Mutex.h>
|
44 kumpf 1.16
|
45 marek 1.47 #if defined(PEGASUS_USE_SYSLOGS)
46 # include <syslog.h>
47 #endif
48
|
49 mike 1.13 PEGASUS_USING_STD;
50
51 PEGASUS_NAMESPACE_BEGIN
52
|
53 mreddy 1.55 // Maximum logfile size is defined as 32 MB = 32 * 1024 * 1024
54 # define PEGASUS_MAX_LOGFILE_SIZE 0X2000000
55
|
56 mike 1.13 const Uint32 Logger::TRACE = (1 << 0);
57 const Uint32 Logger::INFORMATION = (1 << 1);
58 const Uint32 Logger::WARNING = (1 << 2);
59 const Uint32 Logger::SEVERE = (1 << 3);
60 const Uint32 Logger::FATAL = (1 << 4);
61
|
62 david 1.26 static char const* LOGLEVEL_LIST[] =
63 {
64 "TRACE",
65 "INFORMATION",
66 "WARNING",
67 "SEVERE",
68 "FATAL"
69 };
70
|
71 mike 1.13 LoggerRep* Logger::_rep = 0;
72 String Logger::_homeDirectory = ".";
|
73 kumpf 1.16
|
74 david 1.26 const Uint32 Logger::_NUM_LOGLEVEL = 5;
75
|
76 kumpf 1.57 Uint32 Logger::_severityMask;
|
77 david 1.26
|
78 kumpf 1.57 ///////////////////////////////////////////////////////////////////////////////
79 //
80 // LoggerRep
81 //
82 ///////////////////////////////////////////////////////////////////////////////
|
83 kumpf 1.16
|
84 kumpf 1.57 #if defined(PEGASUS_USE_SYSLOGS)
|
85 mike 1.13
|
86 kumpf 1.57 class LoggerRep
87 {
88 public:
|
89 david 1.26
|
90 kumpf 1.57 LoggerRep(const String& homeDirectory)
|
91 mike 1.13 {
|
92 kumpf 1.57 # ifdef PEGASUS_OS_ZOS
93 logIdentity = strdup(System::CIMSERVER.getCString());
94 // If System Log is used open it
95 System::openlog(logIdentity, LOG_PID, LOG_DAEMON);
96 # endif
97 }
|
98 mike 1.13
|
99 kumpf 1.57 ~LoggerRep()
100 {
101 # ifdef PEGASUS_OS_ZOS
102 System::closelog();
103 free(logIdentity);
104 # endif
105 }
|
106 mike 1.13
|
107 kumpf 1.57 // Actual logging is done in this routine
108 void log(Logger::LogFileType logFileType,
109 const String& systemId,
110 Uint32 logLevel,
111 const String localizedMsg)
112 {
113 // Log the message
114 System::syslog(systemId, logLevel, localizedMsg.getCString());
115 }
116
117 private:
118
119 # ifdef PEGASUS_OS_ZOS
120 char* logIdentity;
121 # endif
122 };
123
124 #else // !defined(PEGASUS_USE_SYSLOGS)
125
126 static const char* fileNames[] =
127 {
128 kumpf 1.57 "PegasusTrace.log",
129 "PegasusStandard.log",
130 "PegasusAudit.log",
|
131 ouyang.jian 1.60 "PegasusError.log"
|
132 kumpf 1.57 };
133 static const char* lockFileName = "PegasusLog.lock";
134
135 /*
136 _constructFileName builds the absolute file name from homeDirectory
|
137 mreddy 1.55 and fileName.
138 */
139 static CString _constructFileName(
140 const String& homeDirectory,
141 const char * fileName)
142 {
|
143 mike 1.13 String result;
|
144 kumpf 1.57 result.reserveCapacity(
145 (Uint32)(homeDirectory.size() + 1 + strlen(fileName)));
|
146 kumpf 1.20 result.append(homeDirectory);
147 result.append('/');
|
148 mreddy 1.55 result.append(fileName);
|
149 kumpf 1.22 return result.getCString();
|
150 mike 1.13 }
151
152 class LoggerRep
153 {
154 public:
155
156 LoggerRep(const String& homeDirectory)
157 {
|
158 kumpf 1.40 // Add test for home directory set.
|
159 mike 1.13
|
160 kumpf 1.40 // If home directory does not exist, create it.
161 CString lgDir = homeDirectory.getCString();
|
162 mike 1.13
|
163 kumpf 1.40 if (!System::isDirectory(lgDir))
164 System::makeDirectory(lgDir);
|
165 mike 1.13
|
166 kumpf 1.40 // KS: I put the second test in just in case some trys to create
167 // a completly erronous directory. At least we will get a message
|
168 kumpf 1.48 if (!System::isDirectory(lgDir))
169 {
170 MessageLoaderParms parms("Common.Logger.LOGGING_DISABLED",
171 "Logging Disabled");
|
172 kumpf 1.40
|
173 kumpf 1.48 cerr << MessageLoader::getMessage(parms);
|
174 kumpf 1.40 }
175
|
176 mreddy 1.55 //Filelocks are not used for VMS
|
177 kumpf 1.57 # if !defined(PEGASUS_OS_VMS)
|
178 mreddy 1.55 _loggerLockFileName = _constructFileName(homeDirectory, lockFileName);
179
180 // Open and close a file to make sure that the file exists, on which
181 // file lock is requested
182 FILE *fileLockFilePointer;
183 fileLockFilePointer = fopen(_loggerLockFileName, "a+");
184 if(fileLockFilePointer)
185 {
186 fclose(fileLockFilePointer);
187 }
|
188 kumpf 1.57 # endif
|
189 mreddy 1.55
190 _logFileNames[Logger::TRACE_LOG] = _constructFileName(homeDirectory,
191 fileNames[Logger::TRACE_LOG]);
|
192 kumpf 1.40
|
193 mreddy 1.55 _logFileNames[Logger::STANDARD_LOG] = _constructFileName(homeDirectory,
194 fileNames[Logger::STANDARD_LOG]);
|
195 kumpf 1.40
|
196 kumpf 1.57 # ifdef PEGASUS_ENABLE_AUDIT_LOGGER
|
197 mreddy 1.55 _logFileNames[Logger::AUDIT_LOG] = _constructFileName(homeDirectory,
198 fileNames[Logger::AUDIT_LOG]);
|
199 kumpf 1.57 # endif
|
200 thilo.boehm 1.46
|
201 mreddy 1.55 _logFileNames[Logger::ERROR_LOG] = _constructFileName(homeDirectory,
202 fileNames[Logger::ERROR_LOG]);
|
203 marek 1.47 }
204
205 ~LoggerRep()
206 {
|
207 mreddy 1.55 }
208
209 // Actual logging is done in this routine
210 void log(Logger::LogFileType logFileType,
211 const String& systemId,
212 Uint32 logLevel,
213 const String localizedMsg)
214 {
215 // Prepend the systemId to the incoming message
216 String messageString(systemId);
217 messageString.append(": ");
218 messageString.append(localizedMsg); // l10n
|
219 marek 1.47
|
220 mreddy 1.55 // Get the logLevel String
221 // This converts bitmap to string based on highest order
222 // bit set
223 // ATTN: KS Fix this more efficiently.
224 const char* tmp = "";
225 if (logLevel & Logger::TRACE) tmp = "TRACE ";
226 if (logLevel & Logger::INFORMATION) tmp = "INFO ";
227 if (logLevel & Logger::WARNING) tmp = "WARNING ";
228 if (logLevel & Logger::SEVERE) tmp = "SEVERE ";
229 if (logLevel & Logger::FATAL) tmp = "FATAL ";
|
230 mike 1.13
|
231 mreddy 1.55 # ifndef PEGASUS_OS_VMS
232 // Acquire AutoMutex (for thread sync)
233 // and AutoFileLock (for Process Sync).
234 AutoMutex am(_mutex);
235 AutoFileLock fileLock(_loggerLockFileName);
236
237 Uint32 logFileSize = 0;
238
239 // Read logFileSize to check if the logfile needs to be pruned.
240 FileSystem::getFileSize(String(_logFileNames[logFileType]),
241 logFileSize);
242
243 // Check if the size of the logfile is exceeding 32MB.
244 if ( logFileSize > PEGASUS_MAX_LOGFILE_SIZE)
|
245 kumpf 1.57 {
|
246 mreddy 1.55 // Prepare appropriate file name based on the logFileType.
247 // Eg: if Logfile name is PegasusStandard.log, pruned logfile name
248 // will be PegasusStandard-062607-122302.log,where 062607-122302
249 // is the time stamp.
250 String prunedLogfile(_logFileNames[logFileType],
251 (Uint32)strlen(_logFileNames[logFileType]) - 4);
252 prunedLogfile.append('-');
253
254 // Get timestamp,remove illegal chars in file name'/' and ':'
255 // (: is illegal Open VMS) from the time stamp. Append the time
256 // info to the file name.
|
257 mike 1.13
|
258 mreddy 1.55 String timeStamp = System::getCurrentASCIITime();
259 for (unsigned int i=0; i<=timeStamp.size(); i++)
260 {
261 if(timeStamp[i] == '/' || timeStamp[i] == ':')
262 {
263 timeStamp.remove(i, 1);
264 }
265 }
266 prunedLogfile.append(timeStamp);
|
267 mike 1.13
|
268 mreddy 1.55 // Append '.log' to the file
269 prunedLogfile.append( ".log");
|
270 mike 1.13
|
271 mreddy 1.55 // Rename the logfile
272 FileSystem::renameFile(String(_logFileNames[logFileType]),
273 prunedLogfile);
274
275 } // Check if the logfile needs to be pruned.
276 # endif // ifndef PEGASUS_OS_VMS
277
278 // Open Logfile. Based on the value of logFileType, one of the five
279 // Logfiles will be opened.
280 ofstream logFileStream;
281 logFileStream.open(_logFileNames[logFileType], ios::app);
282 logFileStream << System::getCurrentASCIITime()
283 << " " << tmp << (const char *)messageString.getCString() << endl;
284 logFileStream.close();
|
285 mike 1.13 }
286
287 private:
288
|
289 mreddy 1.55 CString _logFileNames[int(Logger::NUM_LOGS)];
|
290 kumpf 1.57
291 # ifndef PEGASUS_OS_VMS
|
292 mreddy 1.55 CString _loggerLockFileName;
293 Mutex _mutex;
|
294 kumpf 1.57 # endif
|
295 mike 1.13 };
296
|
297 kumpf 1.57 #endif // !defined(PEGASUS_USE_SYSLOGS)
298
299
300 ///////////////////////////////////////////////////////////////////////////////
301 //
302 // Logger
303 //
304 ///////////////////////////////////////////////////////////////////////////////
305
|
306 david 1.26 void Logger::_putInternal(
|
307 mike 1.13 LogFileType logFileType,
308 const String& systemId,
|
309 kumpf 1.48 const Uint32 logComponent, // FUTURE: Support logComponent mask
|
310 david 1.26 Uint32 logLevel,
|
311 kumpf 1.63 const String& message)
|
312 mike 1.13 {
|
313 kumpf 1.63 if (!_rep)
314 _rep = new LoggerRep(_homeDirectory);
|
315 chuck 1.29
|
316 kumpf 1.63 // Call the actual logging routine is in LoggerRep.
317 _rep->log(logFileType, systemId, logLevel, message);
318
319 // route log message to trace too -> component LogMessages
320 if (Logger::TRACE_LOG != logFileType)
321 {
322 // do not write log message to trace when trace facility is
323 // the log to avoid double messages
324 if (Tracer::TRACE_FACILITY_LOG != Tracer::getTraceFacility())
325 {
326 PEG_TRACE_CSTRING(
327 TRC_LOGMSG,
328 Tracer::LEVEL1,
329 (const char*) message.getCString());
|
330 kumpf 1.40 }
|
331 david 1.26 }
332 }
|
333 mike 1.13
|
334 mike 1.42 ////////////////////////////////////////////////////////////////////////////////
335 //
336 // Public methods start here:
337 //
338 ////////////////////////////////////////////////////////////////////////////////
339
|
340 david 1.26 void Logger::put(
|
341 kumpf 1.40 LogFileType logFileType,
342 const String& systemId,
343 Uint32 logLevel,
344 const String& formatString,
345 const Formatter::Arg& arg0,
346 const Formatter::Arg& arg1,
347 const Formatter::Arg& arg2,
348 const Formatter::Arg& arg3,
349 const Formatter::Arg& arg4,
350 const Formatter::Arg& arg5,
351 const Formatter::Arg& arg6,
352 const Formatter::Arg& arg7,
353 const Formatter::Arg& arg8,
354 const Formatter::Arg& arg9)
|
355 chuck 1.29 {
|
356 mike 1.42 if (wouldLog(logLevel))
357 {
358 Logger::_putInternal(logFileType, systemId, 0, logLevel,
|
359 kumpf 1.63 Formatter::format(formatString, arg0, arg1, arg2, arg3,
360 arg4, arg5, arg6, arg7, arg8, arg9));
|
361 mike 1.42 }
|
362 karl 1.37 }
363
364 void Logger::put(
|
365 kumpf 1.40 LogFileType logFileType,
366 const String& systemId,
367 Uint32 logLevel,
368 const String& formatString)
|
369 karl 1.37 {
|
370 mike 1.42 if (wouldLog(logLevel))
371 {
|
372 kumpf 1.63 Logger::_putInternal(logFileType, systemId, 0, logLevel, formatString);
|
373 mike 1.42 }
374 }
|
375 karl 1.37
|
376 mike 1.42 void Logger::put(
377 LogFileType logFileType,
378 const String& systemId,
379 Uint32 logLevel,
380 const String& formatString,
381 const Formatter::Arg& arg0)
382 {
383 if (wouldLog(logLevel))
384 {
385 Logger::_putInternal(logFileType, systemId, 0, logLevel,
|
386 kumpf 1.63 Formatter::format(formatString, arg0));
|
387 mike 1.42 }
|
388 karl 1.37 }
389
390 void Logger::put(
|
391 kumpf 1.40 LogFileType logFileType,
392 const String& systemId,
393 Uint32 logLevel,
394 const String& formatString,
|
395 mike 1.42 const Formatter::Arg& arg0,
396 const Formatter::Arg& arg1)
|
397 karl 1.37 {
|
398 mike 1.42 if (wouldLog(logLevel))
399 {
400 Logger::_putInternal(logFileType, systemId, 0, logLevel,
|
401 kumpf 1.63 Formatter::format(formatString, arg0, arg1));
|
402 mike 1.42 }
403 }
|
404 karl 1.37
|
405 mike 1.42 void Logger::put(
406 LogFileType logFileType,
407 const String& systemId,
408 Uint32 logLevel,
409 const String& formatString,
410 const Formatter::Arg& arg0,
411 const Formatter::Arg& arg1,
412 const Formatter::Arg& arg2)
413 {
414 if (wouldLog(logLevel))
415 {
416 Logger::_putInternal(logFileType, systemId, 0, logLevel,
|
417 kumpf 1.63 Formatter::format(formatString, arg0, arg1, arg2));
|
418 mike 1.42 }
|
419 chuck 1.29 }
420
421 void Logger::put_l(
|
422 kumpf 1.40 LogFileType logFileType,
423 const String& systemId,
424 Uint32 logLevel,
|
425 kumpf 1.63 const MessageLoaderParms& msgParms)
|
426 mike 1.42 {
427 if (wouldLog(logLevel))
428 {
|
429 kumpf 1.63 MessageLoaderParms parms = msgParms;
430 parms.useProcessLocale = true;
|
431 mike 1.42 Logger::_putInternal(logFileType, systemId, 0, logLevel,
|
432 kumpf 1.63 MessageLoader::getMessage(parms));
|
433 mike 1.42 }
|
434 david 1.26 }
435
436 void Logger::trace(
|
437 kumpf 1.40 LogFileType logFileType,
438 const String& systemId,
439 const Uint32 logComponent,
|
440 kumpf 1.62 const String& message)
|
441 chuck 1.29 {
|
442 mike 1.42 if (wouldLog(Logger::TRACE))
443 {
444 Logger::_putInternal(logFileType, systemId, logComponent, Logger::TRACE,
|
445 kumpf 1.63 message);
|
446 mike 1.42 }
|
447 mike 1.13 }
448
449 void Logger::setHomeDirectory(const String& homeDirectory)
450 {
451 _homeDirectory = homeDirectory;
452 }
|
453 david 1.26
454 void Logger::setlogLevelMask( const String logLevelList )
455 {
|
456 karl 1.37 Uint32 logLevelType = 0;
|
457 david 1.26 String logLevelName = logLevelList;
458
459 // Check if logLevel has been specified
460 if (logLevelName != String::EMPTY)
461 {
462 // initialise _severityMask
463 _severityMask = 0;
464
|
465 kumpf 1.40 // Set logLevelType to indicate the level of logging
|
466 david 1.26 // required by the user.
|
467 kumpf 1.40 if (String::equalNoCase(logLevelName,"TRACE"))
468 {
469 logLevelType = Logger::TRACE;
470 }
471 else if (String::equalNoCase(logLevelName,"INFORMATION"))
472 {
473 logLevelType = Logger::INFORMATION;
474 }
475 else if (String::equalNoCase(logLevelName,"WARNING"))
476 {
477 logLevelType = Logger::WARNING;
478 }
479 else if (String::equalNoCase(logLevelName,"SEVERE"))
480 {
481 logLevelType = Logger::SEVERE;
482 }
483 else if (String::equalNoCase(logLevelName,"FATAL"))
484 {
485 logLevelType = Logger::FATAL;
486 }
487 // Setting _severityMask. NOTE: When adding new logLevels
|
488 david 1.26 // it is essential that they are adding in ascending order
489 // based on priority. Once a case statement is true we will
490 // continue to set all following log levels with a higher
491 // priority.
|
492 kumpf 1.40 switch(logLevelType)
493 {
494 case Logger::TRACE:
495 _severityMask |= Logger::TRACE;
496 case Logger::INFORMATION:
497 _severityMask |= Logger::INFORMATION;
498 case Logger::WARNING:
499 _severityMask |= Logger::WARNING;
500 case Logger::SEVERE:
501 _severityMask |= Logger::SEVERE;
502 case Logger::FATAL:
503 _severityMask |= Logger::FATAL;
504 }
|
505 kumpf 1.54
506 Executor::updateLogLevel(logLevelName.getCString());
|
507 david 1.26 }
508 else
509 {
|
510 kumpf 1.40 // Property logLevel not specified, set default value.
511 _severityMask = ~Logger::TRACE;
|
512 kumpf 1.54 Executor::updateLogLevel("INFORMATION");
|
513 david 1.26 }
514 }
515
|
516 mike 1.42 Boolean Logger::isValidlogLevel(const String logLevel)
|
517 david 1.26 {
518 // Validate the logLevel and modify the logLevel argument
519 // to reflect the invalid logLevel
520
521 Uint32 index=0;
522 String logLevelName = String::EMPTY;
523 Boolean validlogLevel=false;
524
525 logLevelName = logLevel;
526
527 if (logLevelName != String::EMPTY)
528 {
|
529 kumpf 1.40 // Lookup the index for logLevel name in _logLevel_LIST
530 index = 0;
531 validlogLevel = false;
532
533 while (index < _NUM_LOGLEVEL)
534 {
535 if (String::equalNoCase(logLevelName, LOGLEVEL_LIST[index]))
536 {
537 // Found logLevel, break from the loop
538 validlogLevel = true;
539 break;
540 }
541 else
542 {
543 index++;
544 }
545 }
|
546 david 1.26 }
547 else
548 {
|
549 kumpf 1.40 // logLevels is empty, it is a valid value so return true
|
550 kumpf 1.57 return true;
|
551 david 1.26 }
552
553 return validlogLevel;
554 }
555
|
556 mike 1.13 PEGASUS_NAMESPACE_END
|