blob: 6958e433a4a9995dd67547d5092a0db858a165da [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 "util/logging-support.h"
#include <glob.h>
#include <sys/stat.h>
#include "common/logging.h"
#include "common/names.h"
using namespace impala;
DEFINE_int32(non_impala_java_vlog, 0, "(Advanced) The log level (equivalent to --v) for "
"non-Impala Java classes (0: INFO, 1 and 2: DEBUG, 3: TRACE)");
// Requires JniUtil::Init() to have been called. Called by the frontend and catalog
// service to log messages to Glog.
extern "C"
JNIEXPORT void JNICALL
Java_org_apache_impala_util_NativeLogger_Log(
JNIEnv* env, jclass caller_class, int severity, jstring msg, jstring file,
int line_number) {
// Mimic the behaviour of VLOG(N) by ignoring verbose log messages when appropriate.
if (severity == TLogLevel::VLOG && !VLOG_IS_ON(1)) return;
if (severity == TLogLevel::VLOG_2 && !VLOG_IS_ON(2)) return;
if (severity == TLogLevel::VLOG_3 && !VLOG_IS_ON(3)) return;
// Unused required argument to GetStringUTFChars
jboolean dummy;
const char* filename = env->GetStringUTFChars(file, &dummy);
const char* str = "";
if (msg != NULL) str = env->GetStringUTFChars(msg, &dummy);
int log_level = google::INFO;
switch (severity) {
case TLogLevel::VLOG:
case TLogLevel::VLOG_2:
case TLogLevel::VLOG_3:
log_level = google::INFO;
break;
case TLogLevel::INFO:
log_level = google::INFO;
break;
case TLogLevel::WARN:
log_level = google::WARNING;
break;
case TLogLevel::ERROR:
log_level = google::ERROR;
break;
case TLogLevel::FATAL:
log_level = google::FATAL;
break;
default:
DCHECK(false) << "Unrecognised TLogLevel: " << log_level;
}
google::LogMessage(filename, line_number, log_level).stream() << string(str);
if (msg != NULL) env->ReleaseStringUTFChars(msg, str);
env->ReleaseStringUTFChars(file, filename);
}
namespace impala {
void InitJvmLoggingSupport() {
JNIEnv* env = getJNIEnv();
JNINativeMethod nm;
jclass native_backend_cl = env->FindClass("org/apache/impala/util/NativeLogger");
nm.name = const_cast<char*>("Log");
nm.signature = const_cast<char*>("(ILjava/lang/String;Ljava/lang/String;I)V");
nm.fnPtr = reinterpret_cast<void*>(::Java_org_apache_impala_util_NativeLogger_Log);
env->RegisterNatives(native_backend_cl, &nm, 1);
EXIT_IF_EXC(env);
}
TLogLevel::type FlagToTLogLevel(int flag) {
switch (flag) {
case 0: return TLogLevel::INFO;
case 1: return TLogLevel::VLOG;
case 2: return TLogLevel::VLOG_2;
case 3:
default: return TLogLevel::VLOG_3;
}
}
void LoggingSupport::DeleteOldLogs(const string& path_pattern, int max_log_files) {
// Ignore bad input or disable log rotation
if (max_log_files <= 0) return;
// Map capturing mtimes, oldest files first
typedef map<time_t, string> LogFileMap;
LogFileMap log_file_mtime;
glob_t result;
int glob_ret = glob(path_pattern.c_str(), GLOB_TILDE, NULL, &result);
if (glob_ret != 0) {
if (glob_ret != GLOB_NOMATCH) {
LOG(ERROR) << "glob failed in LoggingSupport::DeleteOldLogs on " << path_pattern
<< " with ret = " << glob_ret;
}
globfree(&result);
return;
}
for (size_t i = 0; i < result.gl_pathc; ++i) {
// Get the mtime for each match
struct stat stat_val;
if (stat(result.gl_pathv[i], &stat_val) != 0) {
LOG(ERROR) << "Could not read last-modified-timestamp for log file "
<< result.gl_pathv[i] << ", will not delete (error was: "
<< strerror(errno) << ")";
continue;
}
log_file_mtime[stat_val.st_mtime] = result.gl_pathv[i];
}
globfree(&result);
// Iterate over the map and remove oldest log files first when too many
// log files exist
if (log_file_mtime.size() <= max_log_files) return;
int files_to_delete = log_file_mtime.size() - max_log_files;
DCHECK_GT(files_to_delete, 0);
for (LogFileMap::const_reference val: log_file_mtime) {
if (unlink(val.second.c_str()) == 0) {
LOG(INFO) << "Old log file deleted during log rotation: " << val.second;
} else {
LOG(ERROR) << "Failed to delete old log file: "
<< val.second << "(error was: " << strerror(errno) << ")";
}
if (--files_to_delete == 0) break;
}
}
}