javacommons/utils/src/logger.cpp
changeset 21 2a9601315dfc
child 48 e0d6e9bd3ca7
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  ?Description
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <pthread.h>
       
    20 #include <stdio.h>
       
    21 #include <time.h>
       
    22 #include <sys/msg.h>
       
    23 #include <sys/time.h>
       
    24 #include <stdlib.h>
       
    25 #include <string.h>
       
    26 #include <stdarg.h>
       
    27 #include <fcntl.h>
       
    28 #include <string>
       
    29 #include <iostream>
       
    30 #include <sstream>
       
    31 #include <iomanip>
       
    32 
       
    33 #include "jdebug_omj.h"
       
    34 #include "logger.h"
       
    35 #include "javacommonutils.h"
       
    36 
       
    37 #ifdef __SYMBIAN32__
       
    38 #include "unistd.h" //getpid() on Symbian
       
    39 #endif
       
    40 
       
    41 #include "com_nokia_mj_impl_utils_Logger.h"
       
    42 
       
    43 using namespace java::util;
       
    44 
       
    45 
       
    46 // ---------------------------------------------------------
       
    47 //      static class members initialization
       
    48 // ---------------------------------------------------------
       
    49 const char TEntryExitLog::KMethodIn[]  = "--> ";
       
    50 const char TEntryExitLog::KMethodOut[] = "<-- ";
       
    51 
       
    52 const char Logger::KErrorString[]      = "[Err  ]";
       
    53 const char Logger::KWarningString[]    = "[Warn ]";
       
    54 const char Logger::KInfoString[]       = "[Info ]";
       
    55 const char Logger::KDebugString[]      = "[Debug]";
       
    56 
       
    57 const int  Logger::DES_FILE_CLOSED     = -1;
       
    58 const int  Logger::DES_FILE_OVERFLOW   = -2;
       
    59 
       
    60 
       
    61 #ifndef J_LOG_USE_RLOGGER_ENABLED
       
    62 std::vector<int> Logger::i_file_descriptors(sizeof component_list / sizeof component_list[0], DES_FILE_CLOSED);
       
    63 #endif //J_LOG_USE_RLOGGER_ENABLED
       
    64 
       
    65 #ifdef __SYMBIAN32__
       
    66 #include "javaredirector.h"
       
    67 void redirect(const char* aText, TLogLevels aLevel)
       
    68 {
       
    69     switch (aLevel)
       
    70     {
       
    71     case EError:
       
    72     case EWarning:
       
    73     case EInfoPrd:
       
    74     {
       
    75         int len = strlen(aText);
       
    76         TPtr8 ptr((unsigned char*)aText, len, len);
       
    77         Redirector::log(ptr);
       
    78         break;
       
    79     }
       
    80     default:
       
    81         break;
       
    82     }
       
    83 }
       
    84 #endif
       
    85 
       
    86 
       
    87 
       
    88 // ---------------------------------------------------------
       
    89 //      JEntryExitLog::JEntryExitLog
       
    90 // ---------------------------------------------------------
       
    91 OS_EXPORT TEntryExitLog::TEntryExitLog(TComponents a_component,
       
    92                                        const char* a_method_name) :
       
    93         i_component(a_component), i_log_level(EEntryLog), i_method_name(a_method_name)
       
    94 {
       
    95     init();
       
    96 }
       
    97 
       
    98 // ---------------------------------------------------------
       
    99 //      JEntryExitLog::JEntryExitLog
       
   100 // ---------------------------------------------------------
       
   101 OS_EXPORT TEntryExitLog::TEntryExitLog(TComponents a_component,
       
   102                                        int         a_log_level,
       
   103                                        const char* a_method_name) :
       
   104         i_component(a_component), i_log_level(a_log_level), i_method_name(a_method_name)
       
   105 {
       
   106     init();
       
   107 }
       
   108 
       
   109 // ---------------------------------------------------------
       
   110 //      JEntryExitLog::init
       
   111 // ---------------------------------------------------------
       
   112 void TEntryExitLog::init()
       
   113 {
       
   114     if (Logger::LogNeeded() && ((Logger::GetLogLevel() & i_log_level) == i_log_level))
       
   115     {
       
   116         std::string log(KMethodIn);
       
   117         log.append(i_method_name);
       
   118         Logger::Log(i_component, EEntryLog, (char*)log.c_str());
       
   119     }
       
   120 }
       
   121 
       
   122 // ---------------------------------------------------------
       
   123 //      JEntryExitLog::~JEntryExitLog
       
   124 // ---------------------------------------------------------
       
   125 OS_EXPORT TEntryExitLog::~TEntryExitLog()
       
   126 {
       
   127     if (Logger::LogNeeded() && ((Logger::GetLogLevel() & i_log_level) == i_log_level))
       
   128     {
       
   129         std::string log(KMethodOut);
       
   130         log.append(i_method_name);
       
   131         Logger::Log(i_component, EEntryLog, (char*)log.c_str());
       
   132     }
       
   133 }
       
   134 
       
   135 // ---------------------------------------------------------
       
   136 //      Logger::Log()
       
   137 // ---------------------------------------------------------
       
   138 OS_EXPORT void Logger::Log(TComponents a_component, TLogLevels level, const char* format_str, ...)
       
   139 {
       
   140     if (!Logger::LogNeeded() || ((Logger::GetLogLevel() & level) != level))
       
   141     {
       
   142         return;
       
   143     }
       
   144 
       
   145     std::string log_buffer;
       
   146 
       
   147 #ifdef J_LOG_DATE_TIME_ENABLED
       
   148 
       
   149     struct tm *tp;
       
   150 
       
   151 #ifdef __SYMBIAN32__
       
   152     tp = new tm(); //localtime() with pthreads leaks memory in Symbian.
       
   153     TTime symTime;
       
   154     symTime.HomeTime();
       
   155     TDateTime dt = symTime.DateTime();
       
   156     tp->tm_mday = dt.Day()+1;
       
   157     tp->tm_mon = dt.Month();
       
   158     tp->tm_year = dt.Year()-1900;
       
   159     tp->tm_hour = dt.Hour();
       
   160     tp->tm_min = dt.Minute();
       
   161     tp->tm_sec = dt.Second();
       
   162 #else //__SYMBIAN32__
       
   163     time_t t;
       
   164     t = time(NULL);                // get current time in seconds from Epoc
       
   165     tp = localtime(&t);            // fill tm struct w.r.t localtime using localtime
       
   166 #endif //__SYMBIAN32__
       
   167 
       
   168 
       
   169     // ostringstream leaks memory in Symbian when called for the first time
       
   170     std::ostringstream time;
       
   171 
       
   172     time << std::setw(2) << std::setfill('0') << tp->tm_mday << "/";
       
   173     time << std::setw(2) << std::setfill('0') << tp->tm_mon+1 << "/";
       
   174     time << std::setw(2) << std::setfill('0') << tp->tm_year + 1900 << " ";
       
   175 
       
   176     time << std::setw(2) << std::setfill('0') << tp->tm_hour << ":";
       
   177     time << std::setw(2) << std::setfill('0') << tp->tm_min << ":";
       
   178     time << std::setw(2) << std::setfill('0') << tp->tm_sec;
       
   179 
       
   180     log_buffer.append(time.str());
       
   181 
       
   182 
       
   183 #ifdef __SYMBIAN32__
       
   184     delete tp;
       
   185 #endif //__SYMBIAN32__
       
   186 
       
   187 
       
   188 #endif //J_LOG_DATE_TIME_ENABLED
       
   189 
       
   190 
       
   191 #ifdef J_LOG_MILLISEC_ENABLED
       
   192 
       
   193     log_buffer.append(".");
       
   194     std::ostringstream mills;
       
   195 
       
   196 #ifdef __SYMBIAN32__
       
   197     mills << std::setw(6) << std::setfill('0') << dt.MicroSecond();  // max 6 digits for microseconds
       
   198 #else //__SYMBIAN32__
       
   199 
       
   200     struct timeval tv;
       
   201     gettimeofday(&tv, NULL);
       
   202 
       
   203     mills << std::setw(6) << std::setfill('0') << tv.tv_usec;  // max 6 digits for microseconds
       
   204 #endif //__SYMBIAN32__
       
   205 
       
   206     const int ms_precision = 3;
       
   207     log_buffer.append(mills.str(), 0, ms_precision);
       
   208 #endif //J_LOG_MILLISEC_ENABLED
       
   209 
       
   210 
       
   211 #ifdef J_LOG_PID_ENABLED
       
   212 
       
   213     // getpid() leaks memory in Symbian when called for the first time
       
   214     int pid = getpid();
       
   215     std::ostringstream process_id;
       
   216     process_id << " [pid:" <<  std::setw(5) << std::setfill('0') << pid << "] ";
       
   217     log_buffer.append(process_id.str());
       
   218 
       
   219 #endif //J_LOG_PID_ENABLED
       
   220 
       
   221 
       
   222 #ifdef J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   223 
       
   224     //log_buffer.append(component_names[a_component]);
       
   225     log_buffer.append(component_list[a_component].name);
       
   226     log_buffer.append(" ");
       
   227 
       
   228 #endif //J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   229 
       
   230 
       
   231     switch (level)
       
   232     {
       
   233     case EError:
       
   234         log_buffer.append(KErrorString);
       
   235         break;
       
   236 
       
   237     case EWarning:
       
   238         log_buffer.append(KWarningString);
       
   239         break;
       
   240 
       
   241     case EInfo:
       
   242     case EInfoPrd:
       
   243         log_buffer.append(KInfoString);
       
   244         break;
       
   245 
       
   246     default:
       
   247         log_buffer.append(KDebugString);
       
   248 
       
   249     }
       
   250 
       
   251     log_buffer.append(" ");
       
   252 
       
   253     const int log_buf_len = 1024; // big enough for one log line
       
   254 //    char buffer[log_buf_len + 1];
       
   255     ScopedCharArray buffer(log_buf_len + 1);
       
   256 
       
   257     // va_list or vsnprintf() leaks memory in Symbian when called for the first time
       
   258     va_list ap;
       
   259     va_start(ap, format_str);
       
   260 
       
   261     vsnprintf(buffer.get(), log_buf_len, format_str, ap);
       
   262     va_end(ap);
       
   263 
       
   264     log_buffer.append(buffer.get());
       
   265 
       
   266 #ifdef J_LOG_USE_JDEBUG
       
   267     ERROR_STR("%s",log_buffer.c_str());
       
   268     return;
       
   269 #endif //J_LOG_USE_JDEBUG
       
   270 
       
   271     log_buffer.append("\r\n");
       
   272 
       
   273     if (level & (EError | EWarning | EInfoPrd))
       
   274     {
       
   275 #ifdef __SYMBIAN32__
       
   276         // Error & warnign level messages are logged always (to 'java.txt')
       
   277         TInt bufLen = strlen(log_buffer.c_str());
       
   278         TPtr8 ptr8((unsigned char *)log_buffer.c_str(), bufLen, bufLen);
       
   279         RFileLogger::Write(KLogDirectory, KLogFileName, EFileLoggingModeAppendRaw, ptr8);
       
   280 #else
       
   281         printf("%s\n", log_buffer.c_str());
       
   282 #endif //__SYMBIAN32__
       
   283     }
       
   284 
       
   285     Print(log_buffer.c_str(), a_component);
       
   286 
       
   287 #ifdef __SYMBIAN32__
       
   288     redirect(log_buffer.c_str(), level);
       
   289 #endif
       
   290 
       
   291     return;
       
   292 }
       
   293 // ---------------------------------------------------------
       
   294 //      Logger::LogNeeded()
       
   295 // ---------------------------------------------------------
       
   296 bool Logger::LogNeeded()
       
   297 {
       
   298     // Not currently need to be implemented.
       
   299     return true;
       
   300 }
       
   301 
       
   302 // ---------------------------------------------------------
       
   303 //       Logger::GetLogLevel()
       
   304 // ---------------------------------------------------------
       
   305 int Logger::GetLogLevel()
       
   306 {
       
   307 
       
   308 #ifdef  JAVA_HEAVY_LOGGER_ON
       
   309     int level = EError | EWarning | EInfoPrd | EInfo | EEntryLog | EInfoHeavyLoad;
       
   310 #else
       
   311     int level = EError | EWarning | EInfoPrd | EInfo;
       
   312 #endif
       
   313 
       
   314     return level;
       
   315 }
       
   316 
       
   317 
       
   318 // ---------------------------------------------------------
       
   319 //       Logger::Print()
       
   320 // ---------------------------------------------------------
       
   321 void Logger::Print(const char* txt, int index)
       
   322 {
       
   323 
       
   324 #ifdef J_LOG_USE_RLOGGER_ENABLED
       
   325 
       
   326     _LIT(KJavaLogDir, "java\\full");
       
   327 
       
   328 
       
   329 #ifdef J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   330     const char* fileName = component_list[0].log_file; //log_file_names[0];
       
   331 #else //J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   332     const char* fileName = component_list[index].log_file; //log_file_names[index];
       
   333 #endif //J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   334 
       
   335 
       
   336     int logFileNameLen = strlen(fileName);
       
   337     TPtr8 fileNamePtr((unsigned char*)fileName, logFileNameLen, logFileNameLen);
       
   338     RBuf nameBuf;
       
   339     nameBuf.Create(fileNamePtr.MaxLength());
       
   340     nameBuf.Copy(fileNamePtr);
       
   341 
       
   342     TInt len = strlen(txt);
       
   343     TPtr8 ptr((unsigned char*)txt, len, len);
       
   344     RFileLogger::Write(KJavaLogDir, nameBuf, EFileLoggingModeAppendRaw, ptr);
       
   345 
       
   346     nameBuf.Close();
       
   347 
       
   348 #else //J_LOG_USE_RLOGGER_ENABLED
       
   349 
       
   350     int fd = GetFileDescriptor(index);
       
   351     if (fd != DES_FILE_CLOSED)
       
   352     {
       
   353         lseek(fd, 0, SEEK_END);
       
   354         write(fd, txt, strlen(txt));
       
   355     }
       
   356 
       
   357 #endif //J_LOG_USE_RLOGGER_ENABLED
       
   358 }
       
   359 
       
   360 
       
   361 #ifndef J_LOG_USE_RLOGGER_ENABLED
       
   362 
       
   363 // ---------------------------------------------------------
       
   364 //    Logger::GetFileDescriptor
       
   365 // ---------------------------------------------------------
       
   366 int Logger::GetFileDescriptor(int index)
       
   367 {
       
   368     int fd = i_file_descriptors[index];
       
   369 
       
   370     if (fd == DES_FILE_OVERFLOW)
       
   371     {
       
   372         // log overflow
       
   373         return DES_FILE_CLOSED;
       
   374     }
       
   375     if (fd == DES_FILE_CLOSED)
       
   376     {
       
   377         char* bin_dir = getenv("JAVA_BIN_ROOT");
       
   378         if (bin_dir != 0)
       
   379         {
       
   380 
       
   381 #ifdef J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   382             const char* fileName = component_list[0].log_file; //log_file_names[0];
       
   383 #else //J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   384             const char* fileName = component_list[index].log_file; //log_file_names[index];
       
   385 #endif //J_LOG_ALL_LOGS_TO_SINGLE_FILE
       
   386 
       
   387             std::string full_path(bin_dir);
       
   388             full_path.append(1, '/');
       
   389 
       
   390             full_path.append(fileName);
       
   391 
       
   392             fd = open(full_path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
       
   393             i_file_descriptors[index] = fd;
       
   394             if (fd == -1)
       
   395                 DEBUG_STR("logger_thread_function() WARNING: can't open log file %s", full_path.c_str());
       
   396         }
       
   397         else
       
   398         {
       
   399             DEBUG("logger_thread_function() WARNING: JAVA_BIN_ROOT is not defined, ignore logging");
       
   400         }
       
   401     }
       
   402 
       
   403     // check if log file too big
       
   404     struct stat fileStatBuf;
       
   405     if (fstat(fd, &fileStatBuf) != -1)
       
   406     {
       
   407         if (fileStatBuf.st_size > MAX_LOG_FILE_SIZE)
       
   408         {
       
   409             i_file_descriptors[index] = DES_FILE_OVERFLOW; //no more logging to the log file
       
   410 
       
   411             std::string warning("LOG FILE OVERFLOW, PLEASE CLEAN UP \n");
       
   412             lseek(fd, 0, SEEK_END);
       
   413             write(fd, warning.c_str(), warning.length());
       
   414             close(fd);
       
   415             return DES_FILE_CLOSED;
       
   416         }
       
   417     }
       
   418     return fd;
       
   419 }
       
   420 
       
   421 #endif //J_LOG_USE_RLOGGER_ENABLED
       
   422 
       
   423 
       
   424 /**
       
   425  * Class:     com_nokia_mj_impl_utils_Logger
       
   426  * Method:    _logging
       
   427  * Signature: (IILjava/lang/String;)V
       
   428  *
       
   429  * Native static Logger._logging() method write log message to file and
       
   430  * accepting three input parameters:
       
   431  * component id, severity level id of emiting information and tracing information
       
   432  */
       
   433 
       
   434 JNIEXPORT void JNICALL Java_com_nokia_mj_impl_utils_Logger__1logging
       
   435 (JNIEnv *aEnv, jclass, jint aComponent, jint aLevel, jstring aLogString)
       
   436 {
       
   437     const char* log = aEnv->GetStringUTFChars(aLogString, 0);
       
   438 
       
   439     if (aLevel == com_nokia_mj_impl_utils_Logger_EError)
       
   440     {
       
   441         ELOG1((TComponents)aComponent, "%s", log);
       
   442     }
       
   443     else if (aLevel == com_nokia_mj_impl_utils_Logger_EWarning)
       
   444     {
       
   445         WLOG1((TComponents)aComponent, "%s", log);
       
   446     }
       
   447     else if (aLevel == com_nokia_mj_impl_utils_Logger_EInfoPrd)
       
   448     {
       
   449         PLOG1((TComponents)aComponent, "%s", log);
       
   450     }
       
   451     else
       
   452     {
       
   453         LOG1((TComponents)aComponent, EInfo, "%s", log);
       
   454     }
       
   455 
       
   456     aEnv->ReleaseStringUTFChars(aLogString, log);
       
   457 }
       
   458 
       
   459 
       
   460 /*
       
   461  * Class:     com_nokia_mj_impl_utils_Logger
       
   462  * Method:    _loggingException
       
   463  * Signature: (IILjava/lang/String;Ljava/lang/Throwable;Ljava/io/ByteArrayOutputStream;Ljava/io/PrintStream;)V
       
   464  *
       
   465  * Method prints stack trace and Throwable info to log file
       
   466  */
       
   467 JNIEXPORT void JNICALL Java_com_nokia_mj_impl_utils_Logger__1loggingException
       
   468 (JNIEnv *aEnv, jclass /*aClassH*/, jint aComponent, jint aLevel, jstring aLogString,
       
   469  jthrowable aThrowable, jobject aByteStream, jobject aPrintStream)
       
   470 {
       
   471     /* get logging string */
       
   472     const char* log = aEnv->GetStringUTFChars(aLogString, 0);
       
   473 
       
   474     /*
       
   475      * call Throwable.printStackTrace(java.io.PrintStream)
       
   476      * this method is not part of CLDC spec, but it's supported by VM vendors
       
   477      */
       
   478     jclass class_Throwable = aEnv->GetObjectClass(aThrowable);
       
   479     jmethodID methodId = aEnv->GetMethodID(class_Throwable, "printStackTrace", "(Ljava/io/PrintStream;)V");
       
   480     aEnv->CallVoidMethod(aThrowable, methodId, aPrintStream);
       
   481 
       
   482     /* call ByteArrayOutputStream.toString() */
       
   483     jclass class_ByteArrayOutputStream = aEnv->GetObjectClass(aByteStream);
       
   484     methodId = aEnv->GetMethodID(class_ByteArrayOutputStream, "toString", "()Ljava/lang/String;");
       
   485     jstring stacktrace_jstr = (jstring) aEnv->CallObjectMethod(aByteStream, methodId);
       
   486     const char *stacktrace = aEnv->GetStringUTFChars(stacktrace_jstr, 0);
       
   487 
       
   488     if (aLevel == com_nokia_mj_impl_utils_Logger_EError)
       
   489     {
       
   490         ELOG2((TComponents)aComponent, "%s: %s", log, stacktrace);
       
   491     }
       
   492     else if (aLevel == com_nokia_mj_impl_utils_Logger_EWarning)
       
   493     {
       
   494         WLOG2((TComponents)aComponent, "%s: %s", log, stacktrace);
       
   495     }
       
   496     else if (aLevel == com_nokia_mj_impl_utils_Logger_EInfoPrd)
       
   497     {
       
   498         PLOG2((TComponents)aComponent, "%s: %s", log, stacktrace);
       
   499     }
       
   500     else
       
   501     {
       
   502         LOG2((TComponents)aComponent, EInfo, "%s: %s", log, stacktrace);
       
   503     }
       
   504 
       
   505     aEnv->ReleaseStringUTFChars(aLogString, log);
       
   506     aEnv->ReleaseStringUTFChars(stacktrace_jstr, stacktrace);
       
   507 }