blob: 4ee7b90c25634a2b68f7da4aac58382e4c4c1240 [file] [log] [blame]
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "kludge_c++11.h"
#include <memory>
#include "app.h"
#include "Log.h"
#include "SysInfo.h"
#include "ErrorHandling.h"
namespace {
const std::string* theLastErrorMsg = 0;
NopLogAppender nopLogAppender;
class StandardLogAppender : public LogAppender {
public:
virtual void append(const LogEvent& v) {
std::cerr << "[" << v.logLevel << "] "
<< v.fileName
<< ":" << v.lineNum
<< ": " << v.message
<< std::endl;
}
} standardLogAppender;
class LastErrorLogAppender : public LogAppender {
public:
virtual void append(const LogEvent& v) {
std::cerr << app::lastErrorMsg() << std::endl;
}
} lastErrorLogAppender;
class ResetLastErrorMsgAtEndOfScope {
public:
ResetLastErrorMsgAtEndOfScope() {
}
~ResetLastErrorMsgAtEndOfScope() {
JP_NO_THROW(theLastErrorMsg = 0);
}
};
class SetLoggerAtEndOfScope {
public:
SetLoggerAtEndOfScope(
std::unique_ptr<WithExtraLogAppender>& withLogAppender,
LogAppender* lastErrorLogAppender):
withLogAppender(withLogAppender),
lastErrorLogAppender(lastErrorLogAppender) {
}
~SetLoggerAtEndOfScope() {
JP_TRY;
std::unique_ptr<WithExtraLogAppender> other(
new WithExtraLogAppender(*lastErrorLogAppender));
withLogAppender.swap(other);
JP_CATCH_ALL;
}
private:
std::unique_ptr<WithExtraLogAppender>& withLogAppender;
LogAppender* lastErrorLogAppender;
};
} // namespace
namespace app {
LogAppender& defaultLastErrorLogAppender() {
return lastErrorLogAppender;
}
std::string lastErrorMsg() {
if (theLastErrorMsg) {
return *theLastErrorMsg;
}
return "";
}
bool isWithLogging() {
// If JPACKAGE_DEBUG environment variable is set to "true"
// logging is enabled.
return SysInfo::getEnvVariable(
std::nothrow, _T("JPACKAGE_DEBUG")) == _T("true");
}
int launch(const std::nothrow_t&,
LauncherFunc func, LogAppender* lastErrorLogAppender) {
if (isWithLogging()) {
Logger::defaultLogger().setAppender(standardLogAppender);
} else {
Logger::defaultLogger().setAppender(nopLogAppender);
}
LOG_TRACE_FUNCTION();
if (!lastErrorLogAppender) {
lastErrorLogAppender = &defaultLastErrorLogAppender();
}
std::unique_ptr<WithExtraLogAppender> withLogAppender;
std::string errorMsg;
const ResetLastErrorMsgAtEndOfScope resetLastErrorMsg;
JP_TRY;
// This will temporary change log appenders of the default logger
// to save log messages in the default and additional log appenders.
// Log appenders config of the default logger will be restored to
// the original state at function exit automatically.
const SetLoggerAtEndOfScope setLogger(withLogAppender, lastErrorLogAppender);
func();
return 0;
// The point of all these redefines is to save the last raw error message in
// 'theLastErrorMsg' variable.
// By default error messages are saved in exception instances with the details
// of error origin (source file, function name, line number).
// We don't want these details in user error messages. However we still want to
// save full information about the last error in the default log appender.
#undef JP_HANDLE_ERROR
#undef JP_HANDLE_UNKNOWN_ERROR
#undef JP_CATCH_EXCEPTIONS
#define JP_HANDLE_ERROR(e) \
do { \
errorMsg = (tstrings::any() << e.what()).str(); \
theLastErrorMsg = &errorMsg; \
reportError(JP_SOURCE_CODE_POS, e); \
} while(0)
#define JP_HANDLE_UNKNOWN_ERROR \
do { \
errorMsg = "Unknown error"; \
theLastErrorMsg = &errorMsg; \
reportUnknownError(JP_SOURCE_CODE_POS); \
} while(0)
#define JP_CATCH_EXCEPTIONS \
catch (const JpErrorBase& e) { \
errorMsg = (tstrings::any() << e.rawMessage()).str(); \
theLastErrorMsg = &errorMsg; \
try { \
throw; \
} catch (const std::runtime_error& e) { \
reportError(JP_SOURCE_CODE_POS, e); \
} \
} catch (const std::runtime_error& e) { \
errorMsg = lastCRTError(); \
theLastErrorMsg = &errorMsg; \
reportError(JP_SOURCE_CODE_POS, e); \
} \
JP_CATCH_UNKNOWN_EXCEPTION
JP_CATCH_ALL;
#undef JP_HANDLE_ERROR
#undef JP_HANDLE_UNKNOWN_ERROR
#undef JP_CATCH_EXCEPTIONS
#define JP_HANDLE_ERROR(e) JP_REPORT_ERROR(e)
#define JP_HANDLE_UNKNOWN_ERROR JP_REPORT_UNKNOWN_ERROR
#define JP_CATCH_EXCEPTIONS JP_DEFAULT_CATCH_EXCEPTIONS
return 1;
}
} // namespace app