KjellKod / g3log

G3log is an asynchronous, "crash safe", logger that is easy to use with default logging sinks or you can add your own. G3log is made with plain C++14 (C++11 support up to release 1.3.2) with no external libraries (except gtest used for unit tests). G3log is made to be cross-platform, currently running on OSX, Windows and several Linux distros. See Readme below for details of usage.
http://github.com/KjellKod/g3log
The Unlicense
907 stars 270 forks source link

g3Log Crashes the Application #303

Closed Mahendrakumar1985 closed 5 years ago

Mahendrakumar1985 commented 5 years ago

If I initialize and log in sample cpp program having main method, it works properly but when I integrated in my dll project where there is no main method but I have method which I call firstly where i have followed the same code as explained in “https://github.com/KjellKod/g3log/issues/88#issuecomment-219030139”. It generates the log properly but immediately my java’s GUI system get crashed and I get the same error. Please help me to get rid of this.

namespace {
static std::once_flag g_initLogger;
static std::unique_ptr g_logger;
static std::unique_ptr g_loggerHandle;
} // namespace

void InitializeLogging(const std::string& logPrefix, const std::string& logPath) {
std::call_once(g_initLogger, [&] {
g_logger = g3::LogWorker::createLogWorker();
g_loggerHandle = g_logger->addDefaultLogger(logPrefix, logPath);
g3::initializeLogging(g_logger.get());
});
}
bool IsLoggerEnabled() {
return g3::internal::isLoggingInitialized();
}

void ShutdownLogging() {
//g3::internal::shutDownLogging(); // HERE I HAVE commented as I calls internally
g_logger.reset();
}

I CALL ABOVE METHODS IN MY METHOD WHICH I CALL IT FROM MY GUI TOOL BUILT IN JAVA

JNIEXPORT jobjectArray JNICALL Java_com_mydll_loadDLLGetVersion(JNIEnv *env, jobject thisObj)
{
int versionNumber = 0;
string resultStr;
jobjectArray jresultStr = (*env).NewObjectArray(3, (*env).FindClass(“java/lang/String”), NULL);

try
{
// Tried initializing here too however it is crashing
/*
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(“MyG3Log_”, “D:\\G3Logs\\”);
g3::initializeLogging(worker.get());
*/
InitializeLogging(“MyG3Log_”, “D:\\G3Logs\\”);

LOG(INFO) << "Hello1";
LOG(INFO) << "Hello2";
LOG(INFO) << "Hello3";
LOG(INFO) << "Hello4";
LOG(INFO) << "Hello5";
LOG(INFO) << "Hello6";
LOG(INFO) << "Hello7";

ShutdownLogging();
}
}
catch (exception& e)
{
if(handleDLL != NULL) {
UnloadDLLAPI(handleDLL);
}
resultStr += ";";
resultStr += e.what();
}
return jresultStr;
}

I GET BELOW ERROR FROM g3Log

g3log g3FileSink shutdown at: 15:42:22
Log file at: [D:/G3Logs/MyG3Log_20190307-154222.log]

FATAL CALL but logger is NOT initialized
CAUSE: EXCEPTION_ACCESS_VIOLATION
Message:
2019/03/07 15:42:56

***** FATAL EXCEPTION RECEIVED *******

***** Vectored Exception Handler: Received fatal exception EXCEPTION_ACCESS_VIOLATION   PID: 13048

******* STACKDUMP *******
stack dump [0]
stack dump [1]
stack dump [2]
stack dump [3]
stack dump [4]
stack dump [5]
stack dump [6]
stack dump [7]
stack dump [8]
stack dump [9]
stack dump [10]
stack dump [11]
stack dump [12]
stack dump [13]
stack dump [14]
stack dump [15]

I initialized the worker in the method however it crashed the application by throwing fatal errors. I tried to look up all your forums and documentation but i found nothing. As per my understanding i have implemented g3log like below :

Mymethod(){
Step 1. Initialized worker
Strp 2. Log statement to print logs in file.
Step 3. Worker.reset() or g3::internal::shutDownLogging()

// my other application related businesses logic
}

Please accept my sincere apologies as I am new to CPP and I tried to find everything in your source code but all time it crashed my application.

Please help.

KjellKod commented 5 years ago

I'm not sure why your main thread is crashing but there's a few things you should be aware of

  1. nit: don't use static inside a namespace. It's not needed.
  2. What you have provided is not the whole log. I.e. do you even see the log statements that you called? Or do you not see them?
  3. The message you see means that you have had a fatal error after the logger was shut down. Or possibly it's part of the shutdown sequence?
  4. The error you have is clear enough though. You have a memory access violation. Access Violations can occur for basically three reasons. Either you are trying to read data from an invalid address, write data to an invalid address, or read an instruction from an invalid address.

What I have seen in the past, depending on compiler, is that unique_ptr's sometimes are unhappy in a namespace. I'm not sure if it's something with the static nature of their life cycle that causes issue. As a debugging help for you, I'd suggest changing them to shared_ptr (you have to transform it y ourself to a shared_ptr as g3log doesn't do that for you) and see if that works better.

Mahendrakumar1985 commented 5 years ago

If we forget all code code above for a moment , i used the same line of code which is in examples dir ie. main_contract.cpp but that also crash thr application. In that code there is no static or unique_ptr. It works better if i put it in main method of simple cpp program. However , i will remove static and try to use shared_ptr and see what happen.

Mahendrakumar1985 commented 5 years ago

As suggested , I removed static and used _sharedptr that works perfectly until I close my application. As soon I close my application , JVN reported problematic frame , g3::internal::pushFatalMessageToLogger

======= g3Log Crash Report===========
FATAL CALL but logger is NOT initialized
CAUSE: EXCEPTION_ACCESS_VIOLATION
Message: 
2019/03/07 23:58:25 

***** FATAL EXCEPTION RECEIVED ******* 

***** Vectored Exception Handler: Received fatal exception EXCEPTION_ACCESS_VIOLATION   PID: 72988

******* STACKDUMP *******
stack dump [0]  
stack dump [1]   JVM_GetManagementExt
stack dump [2]   JVM_FindSignal
stack dump [3]   JVM_FindSignal
stack dump [4]   JVM_GetManagementExt
stack dump [5]   JVM_GetManagementExt
stack dump [6]   JVM_GetThreadStateNames
stack dump [7]   JVM_FindSignal
stack dump [8]   endthreadex
stack dump [9]   endthreadex
stack dump [10]  BaseThreadInitThunk
stack dump [11]  RtlUserThreadStart

=============JAVA APPLICATION CRASHED REPORT=============

 A fatal error has been detected by the Java Runtime Environment:

 EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffc708fb446, pid=72988, tid=0x000000000000867c

 JRE version: Java(TM) SE Runtime Environment (8.0_171-b11) (build 1.8.0_171-b11)
 Java VM: Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C  [SuperMsgJNI.dll+0xb446]  g3::internal::pushFatalMessageToLogger+0x366

========= 

I also tried keeping worker in method..now nothing is out of scope however giving crash.

Perhaps , in your code there could be something static which might cause this problem. I am not sure but just assuming because If i remove g3Log, works well and as soon as I added piece of code , it crash my application too.

KjellKod commented 5 years ago

Not sure. It's something about the setup and how you deconstruct the logger. Please repost your total setup since you have changed it.

Mahendrakumar1985 commented 5 years ago

Please look at below lines in namespace :

namespace {
std::once_flag g_initLogger;
std::shared_ptr g_logger;
std::shared_ptr g_loggerHandle;
} // namespace

void InitializeLogging(const std::string& logPrefix, const std::string& logPath) {
std::call_once(g_initLogger, [&] {
g_logger = g3::LogWorker::createLogWorker();
g_loggerHandle = g_logger->addDefaultLogger(logPrefix, logPath);
g3::initializeLogging(g_logger.get());
});
}
bool IsLoggerEnabled() {
return g3::internal::isLoggingInitialized();
}

void ShutdownLogging() {
//g3::internal::shutDownLogging(); // HERE I HAVE commented as I calls internally
g_logger.reset();
}

I CALL ABOVE METHODS IN MY METHOD WHICH I CALL IT FROM MY GUI TOOL BUILT IN JAVA

JNIEXPORT jobjectArray JNICALL Java_com_mydll_loadDLLGetVersion(JNIEnv *env, jobject thisObj)
{
int versionNumber = 0;
string resultStr;
jobjectArray jresultStr = (*env).NewObjectArray(3, (*env).FindClass(“java/lang/String”), NULL);

try
{
// Tried initializing here too however it is crashing
/*
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(“MyG3Log_”, “D:\\G3Logs\\”);
g3::initializeLogging(worker.get());
*/
InitializeLogging(“MyG3Log_”, “D:\\G3Logs\\”);

LOG(INFO) << "Hello1";
LOG(INFO) << "Hello2";
LOG(INFO) << "Hello3";
LOG(INFO) << "Hello4";
LOG(INFO) << "Hello5";
LOG(INFO) << "Hello6";
LOG(INFO) << "Hello7";

ShutdownLogging();
}
}
catch (exception& e)
{
if(handleDLL != NULL) {
UnloadDLLAPI(handleDLL);
}
resultStr += ";";
resultStr += e.what();
}
return jresultStr;
}
KjellKod commented 5 years ago

Nitpicking: I’ve updated your comment to be “code wrapped”. Please do that in the future for readability so you don’t have to shout

I.e use

“```”

KjellKod commented 5 years ago

Are the log messages shown in the log file? Please post content of log file

KjellKod commented 5 years ago

Also FYI: the double instatiation above which you commented out was obviously not working. Instantiating g3log twice isn’t supported.

Mahendrakumar1985 commented 5 years ago

That's not double instantiation. One instantiation which is commented , will never be called. In the code above , I have invoked method "initializeLogging() once only. And regarding logs , it generates whatever i am giving to g3Log to print , i don't find any problem there. I don't have logs handy however will post it later.

KjellKod commented 5 years ago
g3::initializeLogging

Cannot be called twice. You wrote earlier that you tried to initialize it here too. That's what I'm saying. Don't do that.

screen shot 2019-03-07 at 1 24 36 pm
Mahendrakumar1985 commented 5 years ago

I don't know what code are you referring. Please find my comments below against initialization :

try
{
// solution 1 which is under method
// Tried initializing here too however it is crashing
/*
auto worker = g3::LogWorker::createLogWorker();
auto handle = worker->addDefaultLogger(“MyG3Log_”, “D:\\G3Logs\\”);
g3::initializeLogging(worker.get()); // this one is commented.
*/

// solution 2 which has method declaration outside of method and worker is instantiated in namespace
InitializeLogging(“MyG3Log_”, “D:\\G3Logs\\”); // This is declared method which I have invoked. So it is the only one initialization.

// common logging for all 2 solution.
LOG(INFO) << "Hello1";
LOG(INFO) << "Hello2";
LOG(INFO) << "Hello3";
LOG(INFO) << "Hello4";
LOG(INFO) << "Hello5";
LOG(INFO) << "Hello6";
LOG(INFO) << "Hello7";

ShutdownLogging();
}
KjellKod commented 5 years ago

Sigh. I won't debate your previous commented out code or not.

To keep this short.

  1. I don't know why your setup is failing. I do not see any issues with your setup as it currently is.
  2. DLLs is not the primary focus on g3log. It does work for many people and they have to go through hoops to get there.
  3. That said,. I have not seen this before. I have also never heard about c++ dlls loaded from a java module so you are in uncharted waters here.
  4. The bug seems to be in the integration of the c++ dll, possibly g3log and Java. I am not aware of what restrictions the JVM puts into using c++ dlls. It's not a bug within g3log but in the integration of the parts OR a limitation and restriction of what you can use within such funky dll setup.

Sorry I can't be of more help. Possibly someone else of the g3log users have seen your ticket here and can be of assistance.

It is interesting that the shared_ptr seemed to work slightly better for you than the unique_ptr. Unless I misunderstood that part ....

g3log uses extensively unique_ptrs. It might be that there are c++ conventions that are not reliable in your setup. Feel free to fork g3log and modify it to your hearts content. If it can be re-used and modified to work for you that's great.

Mahendrakumar1985 commented 5 years ago

Yeah shared_ptr worked better and appreciate for it but i really i don't want someone blame g3Log for crashing the application and also i want to make my application and g3Log totally crash-free as g3Log promise.

Thanks for your help so far. :)

KjellKod commented 5 years ago

g3log has never promised to make anything crash-free. It is crash safe in that it accounts for some type of crashes and dumps the reason for the crash. Avoiding to crash would be a very bad idea.

Good luck

Mahendrakumar1985 commented 5 years ago

shared_ptr also not working. It's also giving crash.

Mahendrakumar1985 commented 5 years ago

I implemented downgraded g2Log version today with the reference of given example and luckily it's working. How's it possible that solution which has been enhanced in g3Log is crashing and older version is working. Also I observed that in g3Log , only initialization crash the application. I haven't printed logs yet. Can you please check ?

KjellKod commented 5 years ago

This makes me suspect that your setup is not C++14 compliant. You can always test the last released version of g3log (see releases).

I have no means of testing your setup. This is not an issue with g3log but with the integration for your specific setup or lack of c++14 support possibly (?).

Let me be clear. If I can help you I will. There’s nothing in this that points to an issue with g3log but rather to the specific setup you are using

Mahendrakumar1985 commented 5 years ago

I am using c++17 so nothing is suspicious but i believe that there is something in g3Log which is crashing while initialization because only 2 lines of code is enough to crash in g3Log. Moreover, I haven't disposed the worker manually however it is properly working as per the testing today.

Mahendrakumar1985 commented 5 years ago

I feel that i am using 1.3.2 version of g3Log and that supports only c++11. Where can I find newer version of g3Log which can support c++14 and this could be the issue of crashing as I am using c++17.

mobileben commented 5 years ago

BTW, just curious, when you say "you're using c++17", does this mean you're building g3log with c++17? Our just compiling your program that you are linking g3log to with C++17.

FWIW, I've used g3log (iOS, Mac, Ubuntu) for my app that was built using C++11, C++14, C++17. I basically upped the versions of C++ for the functionality during development.

I actually recently upgraded version of g3log, having built from my fork (iOS related) synced a couple of days ago from master.

mobileben commented 5 years ago

BTW, if you can get stdout, have you also used other means (besides g3log) to get logging out to see where you are having problems? For example, when in C++ use printf/cout or System.out in Java?

It would give you some more optics. I haven't looked at your code too much or overly pored over the thread. But if you're getting the FATAL EXCEPTION, something in your app is throwing an uncaught exception.

I've had these FATAL EXCEPTIONS before but they have always indeed been an uncaught exception on my end.

KjellKod commented 5 years ago

If you are using master then you are on the c++17 version of g3log.

It shouldn’t be a problem regardless as the c++11 prior versions are compatible with c++14 and 17. C++ is always backwards compatible

Sent from my iPhone

On Mar 9, 2019, at 11:54 AM, mobileben notifications@github.com wrote:

BTW, if you can get stdout, have you also used other means (besides g3log) to get logging out to see where you are having problems? For example, when in C++ use printf/cout or System.out in Java?

It would give you some more optics. I haven't looked at your code too much or overly pored over the thread. But if you're getting the FATAL EXCEPTION, something in your app is throwing an uncaught exception.

I've had these FATAL EXCEPTIONS before but they have always indeed been an uncaught exception on my end.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

Mahendrakumar1985 commented 5 years ago

Yes. I am making my setup in c++17 version and i just checked i have used g3Log 1.3.2 which is latest and c++14 compliant and hopefully should work with c++17 ( please correct if i am wrong here ).

I used simple ofstream before to log into file but that was consuming more memory and that's the reason i am choosing g3Log which is crash-safe and asynchronous. But the fact is g2Log works perfectly by replacing g3Log's code and yesterday only i tried to print 100 millions line and gave me perfect output without any problem so if there is any problem or uncaught exceptions in my code that shouldn't work with g2Log too.

So my observation so far is I get crash while writing line till initialization only. If i write LOG(INFO) that doesn't matters.

Probably i suspect that there could be something which is used in g3Log which might be deprecated in c++17. I am not expert in cpp but just assumes.

mobileben commented 5 years ago

@KjellKod Good to know! My bad, wasn't trying to add to confusion in anything. More just trying to add some verification that it works (at least for me) with C++11/14/17

@Mahendrakumar1985 I would recommend you perhaps try and thin down your external logging (non-g3log based) only for pertinent info so it reduces the memory issues. More importantly you should try and clearly output stuff from the catch. Example:

catch(std::exception& e) {
printf("Exception %s\n", e.what());
}

Note that is simplified. You obviously need to put your own spin on what it needs to do.

The idea here is to capture enough state so you can try and track what is going on. One other thing. I'm not sure how the Java-side effects things. What I mean is whether or not an exception from the Java side can actually be picked up by g3log. So you will also need some logging on the Java side. There is a possibility that your exception is from the Java side. I've worked with Java/JNI before, but admittedly don't have enough knowledge regarding how the two spaces act with regards to exceptions.

I get what you're saying about g2log, but from everything you stated, there is no definitive proof that g3log is really the problem. There isn't enough evidence that proves it conclusively. Apologies if it seems to forward to say that. I've been in enough situations where the "smoking gun" is really a red herring. This is not to say it isn't as you state.

You have an interesting situation with how you are integrating it into your build.

DBJDBJ commented 5 years ago

@Mahendrakumar1985 I assume you know about native Java logging features, end the rest?

Next. On JNI, you might be an expert, but I personally would always make sure the integration layer is written in plain C, not C++.

Mahendrakumar1985 commented 5 years ago

@DBJDBJ i am already maintaining Log4j2 from java side.

I didn't want to put load on JNI's dll by logging from java hence I prefer to create logs from CPP(dll) side.

What if i write JNI layer in C++ ? ( it might be silly question as I don't know C++ more)

I wrote some lines below in my c++ code to see what version it print and it gave me c++98. What does it mean ? Does it mean i am using c++98 ?



int main() {
    if (__cplusplus == 201703L) std::cout << "C++17\n";
    else if (__cplusplus == 201402L) std::cout << "C++14\n";
    else if (__cplusplus == 201103L) std::cout << "C++11\n";
    else if (__cplusplus == 199711L) std::cout << "C++98\n";
    else std::cout << "pre-standard C++\n";
}```
KjellKod commented 5 years ago

From #302 I would say that threaded constructs seems to be extremely limited in a DLL environment. I have very little experience in this area but it seems that the Windows DLL environment cannot be used at all for setup and breakdown of threaded constructs if you use DllMain(...)

You are using something completely different but are possibly within similar restrictions even though this is run through the JVM. Not sure this is of help to you but I think given your troubleshooting and the issues called out above you are probably better off trying a different approach then an asynchronous logger.

If you do find a work around feel free to post it here. As this is not an issue with g3log I consider this closed.