• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/CLog.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017  
00018 #include <spl/types.h>
00019 
00020 #ifdef _WINDOWS
00021 #include <spl/configwin32.h>
00022 #else
00023 #include <spl/autoconf/config.h>
00024 #endif
00025 
00026 #include <spl/Debug.h>
00027 #include <spl/Log.h>
00028 #ifdef HAVE_STRING_H
00029 #include <string.h>
00030 #endif
00031 #ifdef HAVE_TIME_H
00032 #include <time.h>
00033 #endif
00034 #ifdef HAVE_SYS_TIME_H
00035 #include <sys/time.h>
00036 #endif
00037 #include <stdio.h>
00038 #include <spl/Environment.h>
00039 #include <spl/Exception.h>
00040 #include <spl/io/File.h>
00041 #include <spl/Int32.h>
00042 #include <spl/threading/Mutex.h>
00043 #include <spl/text/StringBuffer.h>
00044 #include <spl/net/UdpSocket.h>
00045 
00046 bool Log::_LogDoLog(const Log::LogEntry& le, Log::OutputConfig m_msgToLog)
00047 {
00048         return (le.GetSeverity() == Log::SevAlert && m_msgToLog.m_doLogAlert) ||
00049                 (le.GetSeverity() == Log::SevCritical && m_msgToLog.m_doLogCritical) ||
00050                 (le.GetSeverity() == Log::SevDebug && m_msgToLog.m_doLogDebug) ||
00051                 (le.GetSeverity() == Log::SevEmergency && m_msgToLog.m_doLogEmergency) ||
00052                 (le.GetSeverity() == Log::SevError && m_msgToLog.m_doLogError) ||
00053                 (le.GetSeverity() == Log::SevInfo && m_msgToLog.m_doLogInfo) ||
00054                 (le.GetSeverity() == Log::SevNotice && m_msgToLog.m_doLogNotice) ||
00055                 (le.GetSeverity() == Log::SevWarning && m_msgToLog.m_doLogWarning);
00056 }
00057 
00058 Log::LogEntry::LogEntry()
00059 :       m_facility(Log::FacLocal1), 
00060         m_severity(Log::SevInfo), 
00061         m_dts(),
00062         m_host(Environment::HostName()),
00063         m_process(Environment::ProcessName()),
00064         m_pid(),
00065         m_message()
00066 {
00067 #ifndef _WINDOWS
00068         m_pid = (int)getpid();
00069 #endif
00070 }
00071 
00072 Log::LogEntry::LogEntry(Log::Facility facility, Log::Severity severity, const String& message)
00073 :       m_facility(facility), 
00074         m_severity(severity), 
00075         m_dts(),
00076         m_host(Environment::HostName()),
00077         m_process(Environment::ProcessName()),
00078         m_pid(),
00079         m_message(message)
00080 {
00081 #ifndef _WINDOWS
00082         m_pid = (int)getpid();
00083 #endif
00084 }
00085 
00086 Log::LogEntry::LogEntry(const LogEntry& le)
00087 :       m_facility(le.m_facility), 
00088         m_severity(le.m_severity), 
00089         m_dts(le.m_dts), 
00090         m_host(le.m_host), 
00091         m_process(le.m_process), 
00092         m_pid(le.m_pid),
00093         m_message(le.m_message)
00094 {
00095 }
00096 
00097 Log::LogEntry::LogEntry
00098 (
00099         Log::Facility facility, 
00100         Log::Severity severity, 
00101         const String& host, 
00102         const String& process, 
00103         int pid, 
00104         const String& message
00105 )
00106 :       m_facility(facility), 
00107         m_severity(severity), 
00108         m_dts(),
00109         m_host(host),
00110         m_process(process),
00111         m_pid(pid),
00112         m_message(message)
00113 {
00114 }
00115 
00116 Log::LogEntry::~LogEntry()
00117 {
00118 }
00119 
00120 Log::LogEntry& Log::LogEntry::operator =(const LogEntry& le)
00121 {
00122         m_facility = le.m_facility;
00123         m_severity = le.m_severity; 
00124         m_dts = le.m_dts;
00125         m_host = le.m_host;
00126         m_process = le.m_process;
00127         m_pid = le.m_pid;
00128         m_message = le.m_message;
00129         
00130         return *this;
00131 }
00132 
00133 StringPtr Log::LogEntry::ToString() const
00134 {
00135         StringBuffer buf(30 + m_host.Length() + m_process.Length() + m_message.Length());
00136         buf.Append('<');
00137         buf.Append(Int32::ToString(Priority()));
00138         buf.Append('>');
00139         buf.Append(m_dts.ToStringISO8601());
00140         buf.Append(' ');
00141         buf.Append(m_host);
00142         buf.Append(' ');
00143         buf.Append(m_process);
00144         if (m_pid > 0)
00145         {
00146                 buf.Append('[');
00147                 buf.Append(Int32::ToString(m_pid));
00148                 buf.Append(']');                
00149         }
00150         buf.Append(": ");
00151         buf.Append(m_message);
00152         
00153         if (buf.Length() < 1025)
00154         {
00155                 return buf.ToString();
00156         }
00157         
00158         StringPtr line(buf.ToString());
00159         return line->Substring(0, 1024);
00160 }
00161 
00162 StringPtr Log::LogEntry::ToShortString() const
00163 {
00164         StringBuffer buf(20 + m_message.Length());
00165         buf.Append(m_dts.ToTimeString());
00166         buf.Append(' ');
00167         
00168         switch(m_severity)
00169         {
00170                 case Log::SevEmergency:
00171                         buf.Append("PANIC ");
00172                         break;
00173                 case Log::SevAlert:
00174                         buf.Append("ALERT ");
00175                         break;
00176                 case Log::SevCritical:
00177                         buf.Append("CRITL ");
00178                         break;
00179                 case Log::SevError:
00180                         buf.Append("ERROR ");
00181                         break;
00182                 case Log::SevWarning:
00183                         buf.Append("WARNG ");
00184                         break;
00185                 case Log::SevNotice:
00186                         buf.Append("NOTIC ");
00187                         break;
00188                 case Log::SevInfo:
00189                         buf.Append("INFO: ");
00190                         break;
00191                 case Log::SevDebug:
00192                         buf.Append("DEBUG ");
00193                         break;
00194                 default:
00195                         buf.Append("????? ");
00196                         break;
00197         }
00198         
00199         buf.Append(m_message);
00200         
00201         if (buf.Length() < 1025)
00202         {
00203                 return buf.ToString();
00204         }
00205         
00206         StringPtr line(buf.ToString());
00207         return line->Substring(0, 1024);
00208 }
00209 
00210 Log::LogEntry Log::LogEntry::Parse(const String& msg, unsigned long sourceIp)
00211 {
00212         LogEntry le;
00213         le.GetMessage() = msg;
00214         
00215         struct in_addr ia;
00216         ia.s_addr = sourceIp;
00217         le.GetHost() = String(inet_ntoa(ia));
00218         
00219         if (msg.CharAt(0) != '<')
00220         {
00221                 return le;
00222         }
00223         
00224         int idx = msg.IndexOf('>');
00225         if (0 > idx)
00226         {
00227                 return le;
00228         }
00229         
00230         StringPtr str(msg.Mid(1, idx));
00231         if (! Int32::IsInt(str))
00232         {
00233                 return le;
00234         }
00235         int priority = Int32::Parse(str);
00236         le.GetFacility() = (Log::Facility)(priority / 8);
00237         le.GetSeverity() = (Log::Severity)(priority >> 3);
00238         
00239         int colonPos = msg.LastIndexOf(':');
00240         if (0 > colonPos)
00241         {
00242                 return le;
00243         }
00244         
00245         StringPtr header = msg.Mid(idx+1, colonPos);
00246         StringPtr text = msg.Substring(colonPos + 1)->Trim();
00247         
00248         RefCountPtr<Vector<StringPtr> > parts(header->Split(" "));
00249         if (parts->Count() < 2 || parts->Count() > 4 || ! Date::IsDate(parts->ElementAt(0)))
00250         {
00251                 return le;
00252         }
00253         String sdtm = *parts->ElementAt(0) + " " + *parts->ElementAt(1);
00254         if (! DateTime::IsDateTime(sdtm))
00255         {
00256                 return le;
00257         }
00258         le.GetDateTime() = DateTime::Parse(sdtm);
00259         
00260         le.GetMessage() = msg;
00261         if (parts->Count() > 2)
00262         {
00263                 le.GetHost() = parts->ElementAt(2);
00264         }
00265         if (parts->Count() > 3)
00266         {
00267                 StringPtr tag = parts->ElementAt(3);
00268                 if ((idx = tag->IndexOf('[')) > -1 && tag->IndexOf(']') > -1 )
00269                 {
00270                         le.GetProcess() = tag->Substring(0, idx);
00271                         StringPtr spid = tag->Mid(idx+1, tag->IndexOf(']'));
00272                         if (Int32::IsInt(spid))
00273                         {
00274                                 le.GetPID() = Int32::Parse(spid);
00275                         }
00276                         else
00277                         {
00278                                 le.GetProcess() = tag;
00279                         }
00280                 }
00281                 else
00282                 {
00283                         le.GetProcess() = tag;
00284                 }
00285         }
00286         
00287         return le;
00288 }
00289 
00290 #if defined(DEBUG)
00291 void Log::LogEntry::CheckMem() const
00292 {
00293         m_host.CheckMem();
00294         m_process.CheckMem();
00295         m_message.CheckMem();
00296 }
00297 
00298 void Log::LogEntry::ValidateMem() const
00299 {
00300         m_host.CheckMem();
00301         m_process.CheckMem();
00302         m_message.CheckMem();
00303 }
00304 #endif
00305 
00306 Log::LogServerInfo::LogServerInfo()
00307 : m_server(), m_port(0), m_sock()
00308 {
00309 }
00310 
00311 Log::LogServerInfo::LogServerInfo(const String& server, int port)
00312 : m_server(server), m_port(port), m_sock()
00313 {
00314         m_logMsgTypes.m_doLogAlert = 1;
00315         m_logMsgTypes.m_doLogCritical = 1;
00316         m_logMsgTypes.m_doLogDebug = 1;
00317         m_logMsgTypes.m_doLogEmergency = 1;
00318         m_logMsgTypes.m_doLogError = 1;
00319         m_logMsgTypes.m_doLogInfo = 1;
00320         m_logMsgTypes.m_doLogNotice = 1;
00321         m_logMsgTypes.m_doLogWarning = 1;
00322 
00323         m_sock = UdpSocketPtr(new UdpSocket(server, port));
00324 }
00325 
00326 Log::LogServerInfo::LogServerInfo(const String& server, int port, OutputConfig logMsgTypes)
00327 : m_server(server), m_port(port), m_logMsgTypes(logMsgTypes), m_sock()
00328 {
00329         m_sock = UdpSocketPtr(new UdpSocket(server, port));
00330 }
00331 
00332 Log::LogServerInfo::~LogServerInfo()
00333 {
00334         if (m_sock.IsNotNull())
00335         {
00336                 m_sock->Close();
00337         }
00338 }
00339 
00340 Log::LogServerInfo& Log::LogServerInfo::operator =(const LogServerInfo& lsi)
00341 {
00342         m_server = lsi.m_server;
00343         m_port = lsi.m_port;
00344         m_logMsgTypes = lsi.m_logMsgTypes;
00345         m_sock = lsi.m_sock;
00346 
00347         return *this;
00348 }
00349 
00350 void Log::LogServerInfo::Send(const LogEntry& le)
00351 {
00352         m_sock->Send(le.ToString()->ToByteArray());
00353 }
00354 
00355 void Log::LogServerInfo::Send(const String& line)
00356 {
00357         m_sock->Send(line.ToByteArray());
00358 }
00359 
00360 #if defined(DEBUG)
00361 void Log::LogServerInfo::CheckMem() const
00362 {
00363         m_server.CheckMem();
00364         m_sock.CheckMem();
00365 }
00366 
00367 void Log::LogServerInfo::ValidateMem() const
00368 {
00369         m_server.ValidateMem();
00370         m_sock.ValidateMem();
00371 }
00372 #endif
00373 
00374 Log::Log()
00375 :       m_facility(Log::FacLocal0), 
00376         m_logType(Log::LogToConsole), 
00377         m_messageCount(0), 
00378         m_servers(), 
00379         m_fileName(),
00380         m_msgToLog()
00381 {
00382 }
00383 
00384 Log::Log(Facility facility, LogType logType)
00385 :       m_facility(facility), 
00386         m_logType(logType), 
00387         m_servers(), 
00388         m_messageCount(0), 
00389         m_fileName(),
00390         m_msgToLog()
00391 {
00392 }
00393 
00394 Log::Log(const Log& l)
00395 :       m_facility(l.m_facility), 
00396         m_logType(l.m_logType), 
00397         m_messageCount(l.m_messageCount),
00398         m_fileName(l.m_fileName),
00399         m_servers(l.m_servers)
00400 {
00401         m_msgToLog = l.m_msgToLog;
00402 }
00403 
00404 Log::~Log()
00405 {
00406         for (List<LogServerInfo>::Iterator iter = m_servers.Begin(); iter.Next(); )
00407         {
00408                 iter.CurrentRef().Close();
00409         }
00410 }
00411 
00412 Log& Log::operator =(const Log& l)
00413 {
00414         m_facility = l.m_facility;
00415         m_logType = l.m_logType;
00416         m_messageCount = l.m_messageCount;
00417         m_fileName = l.m_fileName;
00418         m_servers = l.m_servers;
00419         m_msgToLog = l.m_msgToLog;
00420         return *this;
00421 }
00422 
00423 int Log::m_staticLogType = Log::LogToConsole;
00424 char Log::m_staticFileName[512] = {0};
00425 char Log::m_staticServerName[128] = {0};
00426 int Log::m_staticServerPort = 514;
00427 volatile int Log::m_staticMessageCount = 0;
00428 volatile int Log::m_staticOldMsgCount = 0;
00429 
00430 static Mutex g_loglock;
00431 
00432 static void _LogWriteFile(const Log::LogEntry& le, const String& filename)
00433 {
00434         ASSERT(filename.Length() > 0);
00435         
00436         g_loglock.Lock();
00437         
00438         try
00439         {
00440                 TextWriterPtr writer = File::AppendText(filename);
00441                 writer->WriteLine(le.ToString());
00442                 writer->Close();
00443         }
00444         catch(Exception *ex)
00445         {
00446                 printf("Error writing log file (%s) %s\n", filename.GetChars(), ex->Message());
00447                 delete ex;
00448         }
00449         
00450         g_loglock.Unlock();
00451 }
00452 
00453 static void _LogWriteServer(const Log::LogEntry& le, const String& server, int port)
00454 {
00455         ASSERT(server.Length() > 0 && port > 0);
00456         
00457         StringPtr line(le.ToString());
00458         UdpSocket sock(port);
00459         sock.Send(line->ToByteArray(), server);
00460         sock.Close();
00461 }
00462 
00463 static void _LogWriteConsole(const Log::LogEntry& le)
00464 {
00465         g_loglock.Lock();
00466         StringPtr line(le.ToShortString());
00467         printf("%s\n", line->GetChars());
00468         g_loglock.Unlock();
00469 }
00470 
00471 static void _LogWrite(const Log::LogEntry& le, int logType, const String& filename, const String& server, int port)
00472 {
00473         if (0 != (logType & Log::LogToFile) && filename.Length() > 0)
00474         {
00475                 _LogWriteFile(le, filename);
00476         }
00477         if (0 != (logType & Log::LogToServer) && server.Length() > 0)
00478         {
00479                 _LogWriteServer(le, server, port);
00480         }
00481         if (0 != (logType & Log::LogToConsole))
00482         {
00483                 _LogWriteConsole(le);
00484         }
00485 }
00486 
00487 bool Log::DoLog(const LogEntry& le)
00488 {
00489         return _LogDoLog(le, m_msgToLog);
00490 }
00491 
00492 void Log::SWrite(const LogEntry& le)
00493 {
00494         m_staticMessageCount++;
00495         _LogWrite(le, m_staticLogType, m_staticFileName, m_staticServerName, m_staticServerPort);
00496 }
00497 
00498 void Log::Write(const LogEntry& le)
00499 {
00500         if (! DoLog(le))
00501         {
00502                 return;
00503         }
00504         m_messageCount++;
00505 
00506         _LogWrite(le, m_logType, m_fileName, "", 0);
00507 
00508         if (0 != (m_logType & Log::LogToServer) && m_servers.Count() > 0)
00509         {
00510                 for (List<LogServerInfo>::Iterator iter = m_servers.Begin(); iter.Next(); )
00511                 {
00512                         if( _LogDoLog(le, iter.CurrentRef().GetWhereToLog()))
00513                         {
00514                                 iter.CurrentRef().Send(le);
00515                         }
00516                 }
00517         }
00518 }
00519 
00520 void Log::SWriteOkFail( const String& msg )
00521 {
00522         LogEntry le;
00523         
00524         if ( m_staticMessageCount == m_staticOldMsgCount )
00525         {
00526                 le.GetMessage() = msg + " OK";
00527         }
00528         else
00529         {
00530                 le.GetMessage() = msg + " FAIL";
00531         }
00532         SWrite(le);
00533         
00534         m_staticOldMsgCount = m_staticMessageCount;
00535 }
00536 
00537 void Log::SWriteEndOfRunTotal()
00538 {
00539         LogEntry le;
00540         if ( 0 == m_staticMessageCount )
00541         {
00542                 le.GetMessage() = "No errors.";
00543         }
00544         else
00545         {
00546                 le.GetMessage() = "Errors.";
00547         }
00548         SWrite(le);
00549 }
00550 
00551 void Log::Write(const OutOfMemoryException& mex)
00552 {
00553         WriteError(mex.Message());
00554 }
00555 
00556 void Log::Write(Exception *ex)
00557 {
00558         WriteError(ex->Message());
00559 }
00560 
00561 void Log::Write(Severity severity, const String& message)
00562 {
00563         LogEntry le(m_facility, severity, message);
00564         Write(le);
00565 }
00566 
00567 void Log::Write(Severity severity, Facility facility, const String& process, const String& message)
00568 {
00569         LogEntry le(facility, severity, message);
00570         le.GetProcess() = process;
00571         le.GetPID() = 0;
00572         Write(le);
00573 }
00574 
00575 void Log::Write(Severity severity, Facility facility, const String& process, int pid, const String& message)
00576 {
00577         LogEntry le(facility, severity, message);
00578         le.GetProcess() = process;
00579         le.GetPID() = pid;
00580         Write(le);
00581 }
00582 
00583 void Log::Write(Severity severity, Facility facility, const String& host, const String& process, int pid, const String& message)
00584 {
00585         LogEntry le(facility, severity, host, process, pid, message);
00586         Write(le);
00587 }
00588 
00589 void Log::WriteError(const String& message)
00590 {
00591         LogEntry le(m_facility, Log::SevError, message);
00592         Write(le);
00593 }
00594 
00595 void Log::WriteWarn(const String& message)
00596 {
00597         LogEntry le(m_facility, Log::SevWarning, message);
00598         Write(le);      
00599 }
00600 
00601 void Log::WriteInfo(const String& message)
00602 {
00603         LogEntry le(m_facility, Log::SevInfo, message);
00604         Write(le);
00605 }
00606 
00607 void Log::SSetLogType(LogType lt)
00608 {
00609         m_staticLogType = lt;
00610 }
00611 
00612 void Log::SSetLogFileName(const String& filename)
00613 {
00614         spl::StrCpyLen(m_staticFileName, filename.GetChars(), sizeof(m_staticFileName));
00615 }
00616 
00617 void Log::SSetSyslogServer(const String& server)
00618 {
00619         spl::StrCpyLen(m_staticServerName, server.GetChars(), sizeof(m_staticServerName));
00620 }
00621 
00622 void Log::SSetStaticSyslogPort(int port)
00623 {
00624         m_staticServerPort = port;
00625 }
00626 
00627 void Log::SWrite(const OutOfMemoryException& mex)
00628 {
00629         SWriteError(mex.Message());     
00630 }
00631 
00632 void Log::SWrite(Exception *ex)
00633 {
00634         SWriteError(ex->Message());
00635 }
00636 
00637 void Log::SWrite(Severity severity, const String& message)
00638 {
00639         LogEntry le(Log::FacLocal0, severity, message);
00640         SWrite(le);
00641 }
00642 
00643 void Log::SWrite(Severity severity, Facility facility, const String& process, const String& message)
00644 {
00645         LogEntry le(facility, severity, message);
00646         le.GetProcess() = process;
00647         le.GetPID() = 0;
00648         SWrite(le);
00649 }
00650 
00651 void Log::SWrite(Severity severity, Facility facility, const String& process, int pid, const String& message)
00652 {
00653         LogEntry le(facility, severity, message);
00654         le.GetProcess() = process;
00655         le.GetPID() = pid;
00656         SWrite(le);
00657 }
00658 
00659 void Log::SWrite(Severity severity, Facility facility, const String& host, const String& process, int pid, const String& message)
00660 {
00661         LogEntry le(facility, severity, host, process, pid, message);
00662         SWrite(le);
00663 }
00664 
00665 void Log::SWriteError(const String& message)
00666 {
00667         LogEntry le(Log::FacLocal0, Log::SevError, message);
00668         SWrite(le);
00669 }
00670 
00671 void Log::SWriteWarn(const String& message)
00672 {
00673         LogEntry le(Log::FacLocal0, Log::SevWarning, message);
00674         SWrite(le);
00675 }
00676 
00677 void Log::SWriteInfo(const String& message)
00678 {
00679         LogEntry le(Log::FacLocal0, Log::SevInfo, message);
00680         SWrite(le);
00681 }
00682 
00683 int Log::SMessageCount()
00684 {
00685         return m_staticMessageCount;
00686 }
00687 
00688 #if defined(DEBUG)
00689 void Log::CheckMem() const
00690 {
00691         m_fileName.CheckMem();
00692         m_servers.CheckMem();
00693 }
00694 
00695 void Log::ValidateMem() const
00696 {
00697         m_fileName.ValidateMem();
00698         m_servers.ValidateMem();
00699 }
00700 #endif