diff -r f5050f1da672 -r 04becd199f91 javacommons/utils/src/logger.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javacommons/utils/src/logger.cpp Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,507 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: ?Description +* +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jdebug_omj.h" +#include "logger.h" +#include "javacommonutils.h" + +#ifdef __SYMBIAN32__ +#include "unistd.h" //getpid() on Symbian +#endif + +#include "com_nokia_mj_impl_utils_Logger.h" + +using namespace java::util; + + +// --------------------------------------------------------- +// static class members initialization +// --------------------------------------------------------- +const char TEntryExitLog::KMethodIn[] = "--> "; +const char TEntryExitLog::KMethodOut[] = "<-- "; + +const char Logger::KErrorString[] = "[Err ]"; +const char Logger::KWarningString[] = "[Warn ]"; +const char Logger::KInfoString[] = "[Info ]"; +const char Logger::KDebugString[] = "[Debug]"; + +const int Logger::DES_FILE_CLOSED = -1; +const int Logger::DES_FILE_OVERFLOW = -2; + + +#ifndef J_LOG_USE_RLOGGER_ENABLED +std::vector Logger::i_file_descriptors(sizeof component_list / sizeof component_list[0], DES_FILE_CLOSED); +#endif //J_LOG_USE_RLOGGER_ENABLED + +#ifdef __SYMBIAN32__ +#include "javaredirector.h" +void redirect(const char* aText, TLogLevels aLevel) +{ + switch (aLevel) + { + case EError: + case EWarning: + case EInfoPrd: + { + int len = strlen(aText); + TPtr8 ptr((unsigned char*)aText, len, len); + Redirector::log(ptr); + break; + } + default: + break; + } +} +#endif + + + +// --------------------------------------------------------- +// JEntryExitLog::JEntryExitLog +// --------------------------------------------------------- +OS_EXPORT TEntryExitLog::TEntryExitLog(TComponents a_component, + const char* a_method_name) : + i_component(a_component), i_log_level(EEntryLog), i_method_name(a_method_name) +{ + init(); +} + +// --------------------------------------------------------- +// JEntryExitLog::JEntryExitLog +// --------------------------------------------------------- +OS_EXPORT TEntryExitLog::TEntryExitLog(TComponents a_component, + int a_log_level, + const char* a_method_name) : + i_component(a_component), i_log_level(a_log_level), i_method_name(a_method_name) +{ + init(); +} + +// --------------------------------------------------------- +// JEntryExitLog::init +// --------------------------------------------------------- +void TEntryExitLog::init() +{ + if (Logger::LogNeeded() && ((Logger::GetLogLevel() & i_log_level) == i_log_level)) + { + std::string log(KMethodIn); + log.append(i_method_name); + Logger::Log(i_component, EEntryLog, (char*)log.c_str()); + } +} + +// --------------------------------------------------------- +// JEntryExitLog::~JEntryExitLog +// --------------------------------------------------------- +OS_EXPORT TEntryExitLog::~TEntryExitLog() +{ + if (Logger::LogNeeded() && ((Logger::GetLogLevel() & i_log_level) == i_log_level)) + { + std::string log(KMethodOut); + log.append(i_method_name); + Logger::Log(i_component, EEntryLog, (char*)log.c_str()); + } +} + +// --------------------------------------------------------- +// Logger::Log() +// --------------------------------------------------------- +OS_EXPORT void Logger::Log(TComponents a_component, TLogLevels level, const char* format_str, ...) +{ + if (!Logger::LogNeeded() || ((Logger::GetLogLevel() & level) != level)) + { + return; + } + + std::string log_buffer; + +#ifdef J_LOG_DATE_TIME_ENABLED + + struct tm *tp; + +#ifdef __SYMBIAN32__ + tp = new tm(); //localtime() with pthreads leaks memory in Symbian. + TTime symTime; + symTime.HomeTime(); + TDateTime dt = symTime.DateTime(); + tp->tm_mday = dt.Day()+1; + tp->tm_mon = dt.Month(); + tp->tm_year = dt.Year()-1900; + tp->tm_hour = dt.Hour(); + tp->tm_min = dt.Minute(); + tp->tm_sec = dt.Second(); +#else //__SYMBIAN32__ + time_t t; + t = time(NULL); // get current time in seconds from Epoc + tp = localtime(&t); // fill tm struct w.r.t localtime using localtime +#endif //__SYMBIAN32__ + + + // ostringstream leaks memory in Symbian when called for the first time + std::ostringstream time; + + time << std::setw(2) << std::setfill('0') << tp->tm_mday << "/"; + time << std::setw(2) << std::setfill('0') << tp->tm_mon+1 << "/"; + time << std::setw(2) << std::setfill('0') << tp->tm_year + 1900 << " "; + + time << std::setw(2) << std::setfill('0') << tp->tm_hour << ":"; + time << std::setw(2) << std::setfill('0') << tp->tm_min << ":"; + time << std::setw(2) << std::setfill('0') << tp->tm_sec; + + log_buffer.append(time.str()); + + +#ifdef __SYMBIAN32__ + delete tp; +#endif //__SYMBIAN32__ + + +#endif //J_LOG_DATE_TIME_ENABLED + + +#ifdef J_LOG_MILLISEC_ENABLED + + log_buffer.append("."); + std::ostringstream mills; + +#ifdef __SYMBIAN32__ + mills << std::setw(6) << std::setfill('0') << dt.MicroSecond(); // max 6 digits for microseconds +#else //__SYMBIAN32__ + + struct timeval tv; + gettimeofday(&tv, NULL); + + mills << std::setw(6) << std::setfill('0') << tv.tv_usec; // max 6 digits for microseconds +#endif //__SYMBIAN32__ + + const int ms_precision = 3; + log_buffer.append(mills.str(), 0, ms_precision); +#endif //J_LOG_MILLISEC_ENABLED + + +#ifdef J_LOG_PID_ENABLED + + // getpid() leaks memory in Symbian when called for the first time + int pid = getpid(); + std::ostringstream process_id; + process_id << " [pid:" << std::setw(5) << std::setfill('0') << pid << "] "; + log_buffer.append(process_id.str()); + +#endif //J_LOG_PID_ENABLED + + +#ifdef J_LOG_ALL_LOGS_TO_SINGLE_FILE + + //log_buffer.append(component_names[a_component]); + log_buffer.append(component_list[a_component].name); + log_buffer.append(" "); + +#endif //J_LOG_ALL_LOGS_TO_SINGLE_FILE + + + switch (level) + { + case EError: + log_buffer.append(KErrorString); + break; + + case EWarning: + log_buffer.append(KWarningString); + break; + + case EInfo: + case EInfoPrd: + log_buffer.append(KInfoString); + break; + + default: + log_buffer.append(KDebugString); + + } + + log_buffer.append(" "); + + const int log_buf_len = 1024; // big enough for one log line +// char buffer[log_buf_len + 1]; + ScopedCharArray buffer(log_buf_len + 1); + + // va_list or vsnprintf() leaks memory in Symbian when called for the first time + va_list ap; + va_start(ap, format_str); + + vsnprintf(buffer.get(), log_buf_len, format_str, ap); + va_end(ap); + + log_buffer.append(buffer.get()); + +#ifdef J_LOG_USE_JDEBUG + ERROR_STR("%s",log_buffer.c_str()); + return; +#endif //J_LOG_USE_JDEBUG + + log_buffer.append("\r\n"); + + if (level & (EError | EWarning | EInfoPrd)) + { +#ifdef __SYMBIAN32__ + // Error & warnign level messages are logged always (to 'java.txt') + TInt bufLen = strlen(log_buffer.c_str()); + TPtr8 ptr8((unsigned char *)log_buffer.c_str(), bufLen, bufLen); + RFileLogger::Write(KLogDirectory, KLogFileName, EFileLoggingModeAppendRaw, ptr8); +#else + printf("%s\n", log_buffer.c_str()); +#endif //__SYMBIAN32__ + } + + Print(log_buffer.c_str(), a_component); + +#ifdef __SYMBIAN32__ + redirect(log_buffer.c_str(), level); +#endif + + return; +} +// --------------------------------------------------------- +// Logger::LogNeeded() +// --------------------------------------------------------- +bool Logger::LogNeeded() +{ + // Not currently need to be implemented. + return true; +} + +// --------------------------------------------------------- +// Logger::GetLogLevel() +// --------------------------------------------------------- +int Logger::GetLogLevel() +{ + +#ifdef JAVA_HEAVY_LOGGER_ON + int level = EError | EWarning | EInfoPrd | EInfo | EEntryLog | EInfoHeavyLoad; +#else + int level = EError | EWarning | EInfoPrd | EInfo; +#endif + + return level; +} + + +// --------------------------------------------------------- +// Logger::Print() +// --------------------------------------------------------- +void Logger::Print(const char* txt, int index) +{ + +#ifdef J_LOG_USE_RLOGGER_ENABLED + + _LIT(KJavaLogDir, "java\\full"); + + +#ifdef J_LOG_ALL_LOGS_TO_SINGLE_FILE + const char* fileName = component_list[0].log_file; //log_file_names[0]; +#else //J_LOG_ALL_LOGS_TO_SINGLE_FILE + const char* fileName = component_list[index].log_file; //log_file_names[index]; +#endif //J_LOG_ALL_LOGS_TO_SINGLE_FILE + + + int logFileNameLen = strlen(fileName); + TPtr8 fileNamePtr((unsigned char*)fileName, logFileNameLen, logFileNameLen); + RBuf nameBuf; + nameBuf.Create(fileNamePtr.MaxLength()); + nameBuf.Copy(fileNamePtr); + + TInt len = strlen(txt); + TPtr8 ptr((unsigned char*)txt, len, len); + RFileLogger::Write(KJavaLogDir, nameBuf, EFileLoggingModeAppendRaw, ptr); + + nameBuf.Close(); + +#else //J_LOG_USE_RLOGGER_ENABLED + + int fd = GetFileDescriptor(index); + if (fd != DES_FILE_CLOSED) + { + lseek(fd, 0, SEEK_END); + write(fd, txt, strlen(txt)); + } + +#endif //J_LOG_USE_RLOGGER_ENABLED +} + + +#ifndef J_LOG_USE_RLOGGER_ENABLED + +// --------------------------------------------------------- +// Logger::GetFileDescriptor +// --------------------------------------------------------- +int Logger::GetFileDescriptor(int index) +{ + int fd = i_file_descriptors[index]; + + if (fd == DES_FILE_OVERFLOW) + { + // log overflow + return DES_FILE_CLOSED; + } + if (fd == DES_FILE_CLOSED) + { + char* bin_dir = getenv("JAVA_BIN_ROOT"); + if (bin_dir != 0) + { + +#ifdef J_LOG_ALL_LOGS_TO_SINGLE_FILE + const char* fileName = component_list[0].log_file; //log_file_names[0]; +#else //J_LOG_ALL_LOGS_TO_SINGLE_FILE + const char* fileName = component_list[index].log_file; //log_file_names[index]; +#endif //J_LOG_ALL_LOGS_TO_SINGLE_FILE + + std::string full_path(bin_dir); + full_path.append(1, '/'); + + full_path.append(fileName); + + fd = open(full_path.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + i_file_descriptors[index] = fd; + if (fd == -1) + DEBUG_STR("logger_thread_function() WARNING: can't open log file %s", full_path.c_str()); + } + else + { + DEBUG("logger_thread_function() WARNING: JAVA_BIN_ROOT is not defined, ignore logging"); + } + } + + // check if log file too big + struct stat fileStatBuf; + if (fstat(fd, &fileStatBuf) != -1) + { + if (fileStatBuf.st_size > MAX_LOG_FILE_SIZE) + { + i_file_descriptors[index] = DES_FILE_OVERFLOW; //no more logging to the log file + + std::string warning("LOG FILE OVERFLOW, PLEASE CLEAN UP \n"); + lseek(fd, 0, SEEK_END); + write(fd, warning.c_str(), warning.length()); + close(fd); + return DES_FILE_CLOSED; + } + } + return fd; +} + +#endif //J_LOG_USE_RLOGGER_ENABLED + + +/** + * Class: com_nokia_mj_impl_utils_Logger + * Method: _logging + * Signature: (IILjava/lang/String;)V + * + * Native static Logger._logging() method write log message to file and + * accepting three input parameters: + * component id, severity level id of emiting information and tracing information + */ + +JNIEXPORT void JNICALL Java_com_nokia_mj_impl_utils_Logger__1logging +(JNIEnv *aEnv, jclass, jint aComponent, jint aLevel, jstring aLogString) +{ + const char* log = aEnv->GetStringUTFChars(aLogString, 0); + + if (aLevel == com_nokia_mj_impl_utils_Logger_EError) + { + ELOG1((TComponents)aComponent, "%s", log); + } + else if (aLevel == com_nokia_mj_impl_utils_Logger_EWarning) + { + WLOG1((TComponents)aComponent, "%s", log); + } + else if (aLevel == com_nokia_mj_impl_utils_Logger_EInfoPrd) + { + PLOG1((TComponents)aComponent, "%s", log); + } + else + { + LOG1((TComponents)aComponent, EInfo, "%s", log); + } + + aEnv->ReleaseStringUTFChars(aLogString, log); +} + + +/* + * Class: com_nokia_mj_impl_utils_Logger + * Method: _loggingException + * Signature: (IILjava/lang/String;Ljava/lang/Throwable;Ljava/io/ByteArrayOutputStream;Ljava/io/PrintStream;)V + * + * Method prints stack trace and Throwable info to log file + */ +JNIEXPORT void JNICALL Java_com_nokia_mj_impl_utils_Logger__1loggingException +(JNIEnv *aEnv, jclass /*aClassH*/, jint aComponent, jint aLevel, jstring aLogString, + jthrowable aThrowable, jobject aByteStream, jobject aPrintStream) +{ + /* get logging string */ + const char* log = aEnv->GetStringUTFChars(aLogString, 0); + + /* + * call Throwable.printStackTrace(java.io.PrintStream) + * this method is not part of CLDC spec, but it's supported by VM vendors + */ + jclass class_Throwable = aEnv->GetObjectClass(aThrowable); + jmethodID methodId = aEnv->GetMethodID(class_Throwable, "printStackTrace", "(Ljava/io/PrintStream;)V"); + aEnv->CallVoidMethod(aThrowable, methodId, aPrintStream); + + /* call ByteArrayOutputStream.toString() */ + jclass class_ByteArrayOutputStream = aEnv->GetObjectClass(aByteStream); + methodId = aEnv->GetMethodID(class_ByteArrayOutputStream, "toString", "()Ljava/lang/String;"); + jstring stacktrace_jstr = (jstring) aEnv->CallObjectMethod(aByteStream, methodId); + const char *stacktrace = aEnv->GetStringUTFChars(stacktrace_jstr, 0); + + if (aLevel == com_nokia_mj_impl_utils_Logger_EError) + { + ELOG2((TComponents)aComponent, "%s: %s", log, stacktrace); + } + else if (aLevel == com_nokia_mj_impl_utils_Logger_EWarning) + { + WLOG2((TComponents)aComponent, "%s: %s", log, stacktrace); + } + else if (aLevel == com_nokia_mj_impl_utils_Logger_EInfoPrd) + { + PLOG2((TComponents)aComponent, "%s: %s", log, stacktrace); + } + else + { + LOG2((TComponents)aComponent, EInfo, "%s: %s", log, stacktrace); + } + + aEnv->ReleaseStringUTFChars(aLogString, log); + aEnv->ReleaseStringUTFChars(stacktrace_jstr, stacktrace); +}