blob: 6e71e5e37083f7d550a316ccb77f8994871afe99 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <signal.h> // For sigaction(), sigemptyset().
#include <string.h> // For strsignal().
#include <glog/logging.h>
#include <glog/raw_logging.h>
#include <string>
#include <process/once.hpp>
#include <stout/error.hpp>
#include <stout/exit.hpp>
#include <stout/os.hpp>
#include <stout/path.hpp>
#include <stout/stringify.hpp>
#include <stout/try.hpp>
#include "logging/logging.hpp"
using process::Once;
using std::string;
namespace mesos {
namespace internal {
namespace logging {
// Persistent copy of argv0 since InitGoogleLogging requires the
// string we pass to it to be accessible indefinitely.
string argv0;
// NOTE: We use RAW_LOG instead of LOG because RAW_LOG doesn't
// allocate any memory or grab locks. And according to
// https://code.google.com/p/google-glog/issues/detail?id=161
// it should work in 'most' cases in signal handlers.
void handler(int signal)
{
if (signal == SIGTERM) {
RAW_LOG(WARNING, "Received signal SIGTERM; exiting.");
// Setup the default handler for SIGTERM so that we don't print
// a stack trace.
struct sigaction action;
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = SIG_DFL;
sigaction(signal, &action, NULL);
raise(signal);
} else if (signal == SIGPIPE) {
RAW_LOG(WARNING, "Received signal SIGPIPE; escalating to SIGABRT");
raise(SIGABRT);
} else {
RAW_LOG(FATAL, "Unexpected signal in signal handler: %d", signal);
}
}
void initialize(
const string& _argv0,
const Flags& flags,
bool installFailureSignalHandler)
{
static Once* initialized = new Once();
if (initialized->once()) {
return;
}
argv0 = _argv0;
// Set glog's parameters through Google Flags variables.
if (flags.log_dir.isSome()) {
Try<Nothing> mkdir = os::mkdir(flags.log_dir.get());
if (mkdir.isError()) {
EXIT(1) << "Could not initialize logging: Failed to create directory "
<< flags.log_dir.get() << ": " << mkdir.error();
}
FLAGS_log_dir = flags.log_dir.get();
// Do not log to stderr instead of log files.
FLAGS_logtostderr = false;
} else {
// Log to stderr instead of log files.
FLAGS_logtostderr = true;
}
// Log everything to stderr IN ADDITION to log files unless
// otherwise specified.
if (flags.quiet) {
FLAGS_stderrthreshold = 3; // FATAL.
// FLAGS_stderrthreshold is ignored when logging to stderr instead of log files.
// Setting the minimum log level gets around this issue.
if (FLAGS_logtostderr) {
FLAGS_minloglevel = 3; // FATAL.
}
} else {
FLAGS_stderrthreshold = 0; // INFO.
}
FLAGS_logbufsecs = flags.logbufsecs;
google::InitGoogleLogging(argv0.c_str());
VLOG(1) << "Logging to " <<
(flags.log_dir.isSome() ? flags.log_dir.get() : "STDERR");
if (installFailureSignalHandler) {
// Handles SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, SIGTERM
// by default.
google::InstallFailureSignalHandler();
// Set up our custom signal handlers.
struct sigaction action;
action.sa_handler = handler;
// Do not block additional signals while in the handler.
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
// Set up the SIGPIPE signal handler to escalate to SIGABRT
// in order to have the glog handler catch it and print all
// of its lovely information.
if (sigaction(SIGPIPE, &action, NULL) < 0) {
PLOG(FATAL) << "Failed to set sigaction";
}
// We also do not want SIGTERM to dump a stacktrace, as this
// can imply that we crashed, when we were in fact terminated
// by user request.
if (sigaction(SIGTERM, &action, NULL) < 0) {
PLOG(FATAL) << "Failed to set sigaction";
}
}
initialized->done();
}
Try<string> getLogFile(google::LogSeverity severity)
{
if (FLAGS_log_dir.empty()) {
return Error("The 'log_dir' option was not specified");
}
Try<string> basename = os::basename(argv0);
if (basename.isError()) {
return Error(basename.error());
}
if (severity < 0 || google::NUM_SEVERITIES <= severity) {
return Error("Unknown log severity: " + stringify(severity));
}
string suffix(google::GetLogSeverityName(severity));
return path::join(FLAGS_log_dir, basename.get()) + "." + suffix;
}
} // namespace logging {
} // namespace internal {
} // namespace mesos {