blob: 25ed56096959b26c2260ee3de017c3bae5631782 [file] [log] [blame]
// Copyright 2010 Google Inc.
//
// Licensed 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.
// Author: sligocki@google.com (Shawn Ligocki)
#include "pagespeed/apache/apache_message_handler.h"
#include <signal.h>
#include <unistd.h>
#include "pagespeed/apache/apr_timer.h"
#include "pagespeed/apache/log_message_handler.h"
#include "httpd.h"
#include "pagespeed/apache/apache_logging_includes.h"
#include "pagespeed/kernel/base/abstract_mutex.h"
#include "pagespeed/kernel/base/debug.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/timer.h"
namespace {
// This name will be prefixed to every logged message. This could be made
// smaller if people think it's too long. In my opinion it's probably OK,
// and it would be good to let people know where messages are coming from.
const char kModuleName[] = "mod_pagespeed";
// For crash handler's use.
const server_rec* global_server;
} // namespace
extern "C" {
static void signal_handler(int sig) {
// Try to output the backtrace to the log file. Since this may end up
// crashing/deadlocking/etc. we set an alarm() to abort us if it comes to
// that.
alarm(2);
ap_log_error(APLOG_MARK, APLOG_ALERT, APR_SUCCESS, global_server,
"[@%s] CRASH with signal:%d at %s",
net_instaweb::Integer64ToString(getpid()).c_str(),
sig,
net_instaweb::StackTraceString().c_str());
kill(getpid(), SIGKILL);
}
} // extern "C"
namespace net_instaweb {
// filename_prefix of ApacheRewriteDriverFactory is needed to initialize
// SharedCircuarBuffer. However, ApacheRewriteDriverFactory needs
// ApacheMessageHandler before its filename_prefix is set. So we initialize
// ApacheMessageHandler without SharedCircularBuffer first, then initalize its
// SharedCircularBuffer in RootInit() when filename_prefix is set.
ApacheMessageHandler::ApacheMessageHandler(const server_rec* server,
const StringPiece& version,
Timer* timer, AbstractMutex* mutex)
: SystemMessageHandler(timer, mutex),
server_rec_(server),
version_(version.data(), version.size()) {
// Tell log_message_handler about this server_rec and version.
log_message_handler::AddServerConfig(server_rec_, version);
// TODO(jmarantz): consider making this a little terser by default.
// The string we expect in is something like "0.9.1.1-171" and we will
// may be able to pick off some of the 5 fields that prove to be boring.
}
// Installs a signal handler for common crash signals that tries to print
// out a backtrace.
void ApacheMessageHandler::InstallCrashHandler(server_rec* server) {
global_server = server;
signal(SIGTRAP, signal_handler); // On check failures
signal(SIGABRT, signal_handler);
signal(SIGFPE, signal_handler);
signal(SIGSEGV, signal_handler);
}
int ApacheMessageHandler::GetApacheLogLevel(MessageType type) {
switch (type) {
case kInfo:
// TODO(sligocki): Do we want this to be INFO or NOTICE.
return APLOG_INFO;
case kWarning:
return APLOG_WARNING;
case kError:
return APLOG_ERR;
case kFatal:
return APLOG_ALERT;
}
// This should never fall through, but some compilers seem to complain if
// we don't include this.
return APLOG_ALERT;
}
void ApacheMessageHandler::MessageSImpl(
MessageType type, const GoogleString& message) {
int log_level = GetApacheLogLevel(type);
ap_log_error(APLOG_MARK, log_level, APR_SUCCESS, server_rec_,
"[%s %s @%ld] %s",
kModuleName, version_.c_str(), static_cast<long>(getpid()),
message.c_str());
AddMessageToBuffer(type, message);
}
void ApacheMessageHandler::FileMessageSImpl(
MessageType type, const char* file, int line, const GoogleString& message) {
int log_level = GetApacheLogLevel(type);
ap_log_error(APLOG_MARK, log_level, APR_SUCCESS, server_rec_,
"[%s %s @%ld] %s:%d: %s",
kModuleName, version_.c_str(), static_cast<long>(getpid()),
file, line, message.c_str());
}
} // namespace net_instaweb