8046148: JEP 158: Unified JVM Logging
Reviewed-by: coleenp, sla
This commit is contained in:
parent
0835a6e311
commit
3c2211a492
hotspot
make/windows/makefiles
src/share/vm
Xusage.txt
logging
log.hpplogConfiguration.cpplogConfiguration.hpplogDecorations.cpplogDecorations.hpplogDecorators.cpplogDecorators.hpplogDiagnosticCommand.cpplogDiagnosticCommand.hpplogFileOutput.cpplogFileOutput.hpplogFileStreamOutput.cpplogFileStreamOutput.hpplogLevel.cpplogLevel.hpplogOutput.cpplogOutput.hpplogOutputList.cpplogOutputList.hpplogPrefix.hpplogTag.cpplogTag.hpplogTagLevelExpression.cpplogTagLevelExpression.hpplogTagSet.cpplogTagSet.hpp
memory
precompiled
runtime
services
utilities
test/serviceability/logging
@ -163,6 +163,7 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/serial
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/cms
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/gc/g1
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/asm
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/logging
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/memory
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/oops
|
||||
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/prims
|
||||
@ -250,6 +251,9 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi
|
||||
{$(COMMONSRC)\share\vm\asm}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
{$(COMMONSRC)\share\vm\logging}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
{$(COMMONSRC)\share\vm\memory}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
@ -330,6 +334,9 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi
|
||||
{$(ALTSRC)\share\vm\asm}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
{$(ALTSRC)\share\vm\logging}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
{$(ALTSRC)\share\vm\memory}.cpp.obj::
|
||||
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
-Xbootclasspath/p:<directories and zip/jar files separated by ;>
|
||||
prepend in front of bootstrap class path
|
||||
-Xnoclassgc disable class garbage collection
|
||||
-Xlog:<opts> control JVM logging, use -Xlog:help for details
|
||||
-Xloggc:<file> log GC status to a file with time stamps
|
||||
-Xbatch disable background compilation
|
||||
-Xms<size> set initial Java heap size
|
||||
|
139
hotspot/src/share/vm/logging/log.hpp
Normal file
139
hotspot/src/share/vm/logging/log.hpp
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOG_HPP
|
||||
#define SHARE_VM_LOGGING_LOG_HPP
|
||||
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logPrefix.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
//
|
||||
// Logging macros
|
||||
//
|
||||
// Usage:
|
||||
// log_<level>(<comma separated log tags>)(<printf-style log arguments>);
|
||||
// e.g.
|
||||
// log_debug(logging)("message %d", i);
|
||||
//
|
||||
// Note that these macros will not evaluate the arguments unless the logging is enabled.
|
||||
//
|
||||
#define log_error(...) (!log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Error>
|
||||
#define log_warning(...) (!log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Warning>
|
||||
#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
|
||||
#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
|
||||
#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
|
||||
#ifndef PRODUCT
|
||||
#define log_develop(...) (!log_is_enabled(Develop, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Develop>
|
||||
#else
|
||||
#define DUMMY_ARGUMENT_CONSUMER(...)
|
||||
#define log_develop(...) DUMMY_ARGUMENT_CONSUMER
|
||||
#endif
|
||||
|
||||
// Convenience macro to test if the logging is enabled on the specified level for given tags.
|
||||
#define log_is_enabled(level, ...) (Log<LOG_TAGS(__VA_ARGS__)>::is_level(LogLevel::level))
|
||||
|
||||
//
|
||||
// Log class for more advanced logging scenarios.
|
||||
// Has printf-style member functions for each log level (trace(), debug(), etc).
|
||||
//
|
||||
// Also has outputStream compatible API for the different log-levels.
|
||||
// The streams are resource allocated when requested and are accessed through
|
||||
// calls to <level>_stream() functions (trace_stream(), debug_stream(), etc).
|
||||
//
|
||||
// Example usage:
|
||||
// LogHandle(logging) log;
|
||||
// if (log.is_debug()) {
|
||||
// ...
|
||||
// log.debug("result = %d", result).trace(" tracing info");
|
||||
// obj->print_on(log.debug_stream());
|
||||
// }
|
||||
//
|
||||
#define LogHandle(...) Log<LOG_TAGS(__VA_ARGS__)>
|
||||
|
||||
template <LogTagType T0, LogTagType T1 = LogTag::__NO_TAG, LogTagType T2 = LogTag::__NO_TAG, LogTagType T3 = LogTag::__NO_TAG,
|
||||
LogTagType T4 = LogTag::__NO_TAG, LogTagType GuardTag = LogTag::__NO_TAG>
|
||||
class Log VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
static const size_t LogBufferSize = 512;
|
||||
public:
|
||||
// Make sure no more than the maximum number of tags have been given.
|
||||
// The GuardTag allows this to be detected if/when it happens. If the GuardTag
|
||||
// is not __NO_TAG, the number of tags given exceeds the maximum allowed.
|
||||
STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported!
|
||||
|
||||
static bool is_level(LogLevelType level) {
|
||||
return LogTagSetMapping<T0, T1, T2, T3, T4>::tagset().is_level(level);
|
||||
}
|
||||
|
||||
template <LogLevelType Level>
|
||||
ATTRIBUTE_PRINTF(1, 2)
|
||||
static void write(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vwrite<Level>(fmt, args);
|
||||
va_end(args);
|
||||
};
|
||||
|
||||
template <LogLevelType Level>
|
||||
ATTRIBUTE_PRINTF(1, 0)
|
||||
static void vwrite(const char* fmt, va_list args) {
|
||||
char buf[LogBufferSize];
|
||||
size_t prefix_len = LogPrefix<T0, T1, T2, T3, T4>::prefix(buf, sizeof(buf));
|
||||
int ret = vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args);
|
||||
assert(ret >= 0 && (size_t)ret < sizeof(buf), "Log message too long");
|
||||
puts<Level>(buf);
|
||||
}
|
||||
|
||||
template <LogLevelType Level>
|
||||
static void puts(const char* string) {
|
||||
LogTagSetMapping<T0, T1, T2, T3, T4>::tagset().log(Level, string);
|
||||
}
|
||||
|
||||
#define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \
|
||||
Log& v##name(const char* fmt, va_list args) { \
|
||||
vwrite<LogLevel::level>(fmt, args); \
|
||||
return *this; \
|
||||
} \
|
||||
Log& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { \
|
||||
va_list args; \
|
||||
va_start(args, fmt); \
|
||||
vwrite<LogLevel::level>(fmt, args); \
|
||||
va_end(args); \
|
||||
return *this; \
|
||||
} \
|
||||
static bool is_##name() { \
|
||||
return is_level(LogLevel::level); \
|
||||
} \
|
||||
static outputStream* name##_stream() { \
|
||||
return new logStream(write<LogLevel::level>); \
|
||||
}
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOG_HPP
|
353
hotspot/src/share/vm/logging/logConfiguration.cpp
Normal file
353
hotspot/src/share/vm/logging/logConfiguration.cpp
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logDecorations.hpp"
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "logging/logDiagnosticCommand.hpp"
|
||||
#include "logging/logFileOutput.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "logging/logTagLevelExpression.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
LogOutput** LogConfiguration::_outputs = NULL;
|
||||
size_t LogConfiguration::_n_outputs = 0;
|
||||
|
||||
void LogConfiguration::post_initialize() {
|
||||
assert(LogConfiguration_lock != NULL, "Lock must be initialized before post-initialization");
|
||||
LogDiagnosticCommand::registerCommand();
|
||||
LogHandle(logging) log;
|
||||
log.info("Log configuration fully initialized.");
|
||||
if (log.is_trace()) {
|
||||
ResourceMark rm;
|
||||
MutexLocker ml(LogConfiguration_lock);
|
||||
describe(log.trace_stream());
|
||||
}
|
||||
}
|
||||
|
||||
void LogConfiguration::initialize(jlong vm_start_time) {
|
||||
LogFileOutput::set_file_name_parameters(vm_start_time);
|
||||
LogDecorations::set_vm_start_time_millis(vm_start_time);
|
||||
|
||||
assert(_outputs == NULL, "Should not initialize _outputs before this function, initialize called twice?");
|
||||
_outputs = NEW_C_HEAP_ARRAY(LogOutput*, 2, mtLogging);
|
||||
_outputs[0] = LogOutput::Stdout;
|
||||
_outputs[1] = LogOutput::Stderr;
|
||||
_n_outputs = 2;
|
||||
}
|
||||
|
||||
void LogConfiguration::finalize() {
|
||||
for (size_t i = 2; i < _n_outputs; i++) {
|
||||
delete _outputs[i];
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(LogOutput*, _outputs);
|
||||
}
|
||||
|
||||
size_t LogConfiguration::find_output(const char* name) {
|
||||
for (size_t i = 0; i < _n_outputs; i++) {
|
||||
if (strcmp(_outputs[i]->name(), name) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
LogOutput* LogConfiguration::new_output(char* name, const char* options) {
|
||||
const char* type;
|
||||
char* equals_pos = strchr(name, '=');
|
||||
if (equals_pos == NULL) {
|
||||
type = "file";
|
||||
} else {
|
||||
*equals_pos = '\0';
|
||||
type = name;
|
||||
name = equals_pos + 1;
|
||||
}
|
||||
|
||||
LogOutput* output;
|
||||
if (strcmp(type, "file") == 0) {
|
||||
output = new LogFileOutput(name);
|
||||
} else {
|
||||
// unsupported log output type
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool success = output->initialize(options);
|
||||
if (!success) {
|
||||
delete output;
|
||||
return NULL;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
size_t LogConfiguration::add_output(LogOutput* output) {
|
||||
size_t idx = _n_outputs++;
|
||||
_outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
|
||||
_outputs[idx] = output;
|
||||
return idx;
|
||||
}
|
||||
|
||||
void LogConfiguration::delete_output(size_t idx) {
|
||||
assert(idx > 1 && idx < _n_outputs,
|
||||
err_msg("idx must be in range 1 < idx < _n_outputs, but idx = " SIZE_FORMAT
|
||||
" and _n_outputs = " SIZE_FORMAT, idx, _n_outputs));
|
||||
LogOutput* output = _outputs[idx];
|
||||
// Swap places with the last output and shrink the array
|
||||
_outputs[idx] = _outputs[--_n_outputs];
|
||||
_outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging);
|
||||
delete output;
|
||||
}
|
||||
|
||||
void LogConfiguration::configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators) {
|
||||
assert(idx < _n_outputs, err_msg("Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs));
|
||||
LogOutput* output = _outputs[idx];
|
||||
output->set_decorators(decorators);
|
||||
output->set_config_string(tag_level_expression.to_string());
|
||||
bool enabled = false;
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
LogLevelType level = tag_level_expression.level_for(*ts);
|
||||
if (level != LogLevel::Off) {
|
||||
enabled = true;
|
||||
}
|
||||
ts->update_decorators(decorators);
|
||||
ts->set_output_level(output, level);
|
||||
}
|
||||
|
||||
// If the output is not used by any tagset it should be removed, unless it is stdout/stderr.
|
||||
if (!enabled && idx > 1) {
|
||||
delete_output(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void LogConfiguration::disable_output(size_t idx) {
|
||||
LogOutput* out = _outputs[idx];
|
||||
LogDecorators empty_decorators;
|
||||
empty_decorators.clear();
|
||||
|
||||
// Remove the output from all tagsets.
|
||||
for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) {
|
||||
ts->set_output_level(out, LogLevel::Off);
|
||||
ts->update_decorators(empty_decorators);
|
||||
}
|
||||
|
||||
// Delete the output unless stdout/stderr
|
||||
if (out != LogOutput::Stderr && out != LogOutput::Stdout) {
|
||||
delete_output(find_output(out->name()));
|
||||
} else {
|
||||
out->set_config_string("all=off");
|
||||
}
|
||||
}
|
||||
|
||||
void LogConfiguration::disable_logging() {
|
||||
assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
|
||||
"LogConfiguration lock must be held when calling this function");
|
||||
for (size_t i = 0; i < _n_outputs; i++) {
|
||||
disable_output(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool LogConfiguration::parse_command_line_arguments(const char* opts) {
|
||||
char* copy = os::strdup_check_oom(opts, mtLogging);
|
||||
|
||||
// Split the option string to its colon separated components.
|
||||
char* what = NULL;
|
||||
char* output_str = NULL;
|
||||
char* decorators_str = NULL;
|
||||
char* output_options = NULL;
|
||||
|
||||
what = copy;
|
||||
char* colon = strchr(what, ':');
|
||||
if (colon != NULL) {
|
||||
*colon = '\0';
|
||||
output_str = colon + 1;
|
||||
colon = strchr(output_str, ':');
|
||||
if (colon != NULL) {
|
||||
*colon = '\0';
|
||||
decorators_str = colon + 1;
|
||||
colon = strchr(decorators_str, ':');
|
||||
if (colon != NULL) {
|
||||
*colon = '\0';
|
||||
output_options = colon + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse each argument
|
||||
char errbuf[512];
|
||||
stringStream ss(errbuf, sizeof(errbuf));
|
||||
bool success = parse_log_arguments(output_str, what, decorators_str, output_options, &ss);
|
||||
if (!success) {
|
||||
errbuf[strlen(errbuf) - 1] = '\0'; // Strip trailing newline.
|
||||
log_error(logging)("%s", errbuf);
|
||||
}
|
||||
|
||||
os::free(copy);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool LogConfiguration::parse_log_arguments(const char* outputstr,
|
||||
const char* what,
|
||||
const char* decoratorstr,
|
||||
const char* output_options,
|
||||
outputStream* errstream) {
|
||||
assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
|
||||
"LogConfiguration lock must be held when calling this function");
|
||||
if (outputstr == NULL || strlen(outputstr) == 0) {
|
||||
outputstr = "stdout";
|
||||
}
|
||||
|
||||
size_t idx;
|
||||
if (outputstr[0] == '#') {
|
||||
int ret = sscanf(outputstr+1, SIZE_FORMAT, &idx);
|
||||
if (ret != 1 || idx >= _n_outputs) {
|
||||
errstream->print_cr("Invalid output index '%s'", outputstr);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
idx = find_output(outputstr);
|
||||
if (idx == SIZE_MAX) {
|
||||
char* tmp = os::strdup_check_oom(outputstr, mtLogging);
|
||||
LogOutput* output = new_output(tmp, output_options);
|
||||
os::free(tmp);
|
||||
if (output == NULL) {
|
||||
errstream->print("Unable to add output '%s'", outputstr);
|
||||
if (output_options != NULL && strlen(output_options) > 0) {
|
||||
errstream->print(" with options '%s'", output_options);
|
||||
}
|
||||
errstream->cr();
|
||||
return false;
|
||||
}
|
||||
idx = add_output(output);
|
||||
} else if (output_options != NULL && strlen(output_options) > 0) {
|
||||
errstream->print_cr("Output options for existing outputs are ignored.");
|
||||
}
|
||||
}
|
||||
|
||||
LogTagLevelExpression expr;
|
||||
if (!expr.parse(what, errstream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LogDecorators decorators;
|
||||
if (!decorators.parse(decoratorstr, errstream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
configure_output(idx, expr, decorators);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogConfiguration::describe(outputStream* out) {
|
||||
assert(LogConfiguration_lock == NULL || LogConfiguration_lock->owned_by_self(),
|
||||
"LogConfiguration lock must be held when calling this function");
|
||||
|
||||
out->print("Available log levels:");
|
||||
for (size_t i = 0; i < LogLevel::Count; i++) {
|
||||
out->print("%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
|
||||
}
|
||||
out->cr();
|
||||
|
||||
out->print("Available log decorators:");
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
|
||||
out->print("%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
|
||||
}
|
||||
out->cr();
|
||||
|
||||
out->print("Available log tags:");
|
||||
for (size_t i = 1; i < LogTag::Count; i++) {
|
||||
out->print("%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i)));
|
||||
}
|
||||
out->cr();
|
||||
|
||||
out->print_cr("Log output configuration:");
|
||||
for (size_t i = 0; i < _n_outputs; i++) {
|
||||
out->print("#" SIZE_FORMAT ": %s %s ", i, _outputs[i]->name(), _outputs[i]->config_string());
|
||||
for (size_t d = 0; d < LogDecorators::Count; d++) {
|
||||
LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
|
||||
if (_outputs[i]->decorators().is_decorator(decorator)) {
|
||||
out->print("%s,", LogDecorators::name(decorator));
|
||||
}
|
||||
}
|
||||
out->cr();
|
||||
}
|
||||
}
|
||||
|
||||
void LogConfiguration::print_command_line_help(FILE* out) {
|
||||
jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n"
|
||||
"\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n"
|
||||
"\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n");
|
||||
|
||||
jio_fprintf(out, "Available log levels:\n");
|
||||
for (size_t i = 0; i < LogLevel::Count; i++) {
|
||||
jio_fprintf(out, "%s %s", (i == 0 ? "" : ","), LogLevel::name(static_cast<LogLevelType>(i)));
|
||||
}
|
||||
|
||||
jio_fprintf(out, "\n\nAvailable log decorators: \n");
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
LogDecorators::Decorator d = static_cast<LogDecorators::Decorator>(i);
|
||||
jio_fprintf(out, "%s %s (%s)", (i == 0 ? "" : ","), LogDecorators::name(d), LogDecorators::abbreviation(d));
|
||||
}
|
||||
jio_fprintf(out, "\n Decorators can also be specified as 'none' for no decoration.\n\n");
|
||||
|
||||
jio_fprintf(out, "Available log tags:\n");
|
||||
for (size_t i = 1; i < LogTag::Count; i++) {
|
||||
jio_fprintf(out, "%s %s", (i == 1 ? "" : ","), LogTag::name(static_cast<LogTagType>(i)));
|
||||
}
|
||||
jio_fprintf(out, "\n Specifying 'all' instead of a tag combination matches all tag combinations.\n\n");
|
||||
|
||||
jio_fprintf(out, "Available log outputs:\n"
|
||||
" stdout, stderr, file=<filename>\n"
|
||||
" Specifying %%p and/or %%t in the filename will expand to the JVM's PID and startup timestamp, respectively.\n\n"
|
||||
|
||||
"Some examples:\n"
|
||||
" -Xlog\n"
|
||||
"\t Log all messages using 'info' level to stdout with 'uptime', 'levels' and 'tags' decorations.\n"
|
||||
"\t (Equivalent to -Xlog:all=info:stdout:uptime,levels,tags).\n\n"
|
||||
|
||||
" -Xlog:gc\n"
|
||||
"\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n"
|
||||
|
||||
" -Xlog:gc=debug:file=gc.txt:none\n"
|
||||
"\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n"
|
||||
|
||||
" -Xlog:gc=trace:file=gctrace.txt:uptimemillis,pids:filecount=5,filesize=1024\n"
|
||||
"\t Log messages tagged with 'gc' tag using 'trace' level to a rotating fileset of 5 files of size 1MB,\n"
|
||||
"\t using the base name 'gctrace.txt', with 'uptimemillis' and 'pid' decorations.\n\n"
|
||||
|
||||
" -Xlog:gc::uptime,tid\n"
|
||||
"\t Log messages tagged with 'gc' tag using 'info' level to output 'stdout', using 'uptime' and 'tid' decorations.\n\n"
|
||||
|
||||
" -Xlog:gc*=info,rt*=off\n"
|
||||
"\t Log messages tagged with at least 'gc' using 'info' level, but turn off logging of messages tagged with 'rt'.\n"
|
||||
"\t (Messages tagged with both 'gc' and 'rt' will not be logged.)\n\n"
|
||||
|
||||
" -Xlog:disable -Xlog:rt=trace:rttrace.txt\n"
|
||||
"\t Turn off all logging, including warnings and errors,\n"
|
||||
"\t and then enable messages tagged with 'rt' using 'trace' level to file 'rttrace.txt'.\n");
|
||||
}
|
90
hotspot/src/share/vm/logging/logConfiguration.hpp
Normal file
90
hotspot/src/share/vm/logging/logConfiguration.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGCONFIGURATION_HPP
|
||||
#define SHARE_VM_LOGGING_LOGCONFIGURATION_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogOutput;
|
||||
class LogDecorators;
|
||||
class LogTagLevelExpression;
|
||||
|
||||
// Global configuration of logging. Handles parsing and configuration of the logging framework,
|
||||
// and manages the list of configured log outputs. The actual tag and level configuration is
|
||||
// kept implicitly in the LogTagSets and their LogOutputLists. During configuration the tagsets
|
||||
// are iterated over and updated accordingly.
|
||||
class LogConfiguration : public AllStatic {
|
||||
private:
|
||||
static LogOutput** _outputs;
|
||||
static size_t _n_outputs;
|
||||
|
||||
// Create a new output. Returns NULL if failed.
|
||||
static LogOutput* new_output(char* name, const char* options = NULL);
|
||||
|
||||
// Add an output to the list of configured outputs. Returns the assigned index.
|
||||
static size_t add_output(LogOutput* out);
|
||||
|
||||
// Delete a configured output. The stderr/stdout outputs can not be removed.
|
||||
// Output should be completely disabled before it is deleted.
|
||||
static void delete_output(size_t idx);
|
||||
|
||||
// Disable all logging to the specified output and then delete it (unless it is stdout/stderr).
|
||||
static void disable_output(size_t idx);
|
||||
|
||||
// Get output index by name. Returns SIZE_MAX if output not found.
|
||||
static size_t find_output(const char* name);
|
||||
|
||||
// Configure output (add or update existing configuration) to log on tag-level combination using specified decorators.
|
||||
static void configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators);
|
||||
|
||||
public:
|
||||
// Initialization and finalization of log configuration, to be run at vm startup and shutdown respectively.
|
||||
static void initialize(jlong vm_start_time);
|
||||
static void finalize();
|
||||
|
||||
// Perform necessary post-initialization after VM startup. Enables reconfiguration of logging.
|
||||
static void post_initialize();
|
||||
|
||||
// Disable all logging, equivalent to -Xlog:disable.
|
||||
static void disable_logging();
|
||||
|
||||
// Parse command line configuration. Parameter 'opts' is the string immediately following the -Xlog: argument ("gc" for -Xlog:gc).
|
||||
static bool parse_command_line_arguments(const char* opts = "all");
|
||||
|
||||
// Parse separated configuration arguments (from JCmd/MBean and command line).
|
||||
static bool parse_log_arguments(const char* outputstr,
|
||||
const char* what,
|
||||
const char* decoratorstr,
|
||||
const char* output_options,
|
||||
outputStream* errstream);
|
||||
|
||||
// Prints log configuration to outputStream, used by JCmd/MBean.
|
||||
static void describe(outputStream* out);
|
||||
|
||||
// Prints usage help for command line log configuration.
|
||||
static void print_command_line_help(FILE* out);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGCONFIGURATION_HPP
|
111
hotspot/src/share/vm/logging/logDecorations.cpp
Normal file
111
hotspot/src/share/vm/logging/logDecorations.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logDecorations.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "services/management.hpp"
|
||||
|
||||
jlong LogDecorations::_vm_start_time_millis = 0;
|
||||
|
||||
LogDecorations::LogDecorations(LogLevelType level, const LogTagSet &tagset, const LogDecorators &decorators)
|
||||
: _level(level), _tagset(tagset), _millis(-1) {
|
||||
create_decorations(decorators);
|
||||
}
|
||||
|
||||
void LogDecorations::create_decorations(const LogDecorators &decorators) {
|
||||
char* position = _decorations_buffer;
|
||||
#define DECORATOR(full_name, abbr) \
|
||||
if (decorators.is_decorator(LogDecorators::full_name##_decorator)) { \
|
||||
_decoration_offset[LogDecorators::full_name##_decorator] = position; \
|
||||
position = create_##full_name##_decoration(position) + 1; \
|
||||
}
|
||||
DECORATOR_LIST
|
||||
#undef DECORATOR
|
||||
}
|
||||
|
||||
jlong LogDecorations::java_millis() {
|
||||
if (_millis < 0) {
|
||||
_millis = os::javaTimeMillis();
|
||||
}
|
||||
return _millis;
|
||||
}
|
||||
|
||||
#define ASSERT_AND_RETURN(written, pos) \
|
||||
assert(written >= 0, "Decorations buffer overflow"); \
|
||||
return pos + written;
|
||||
|
||||
char* LogDecorations::create_time_decoration(char* pos) {
|
||||
char* buf = os::iso8601_time(pos, 29);
|
||||
int written = buf == NULL ? -1 : 29;
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char * LogDecorations::create_uptime_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%.3fs", os::elapsedTime());
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char * LogDecorations::create_timemillis_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ms", java_millis());
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char * LogDecorations::create_uptimemillis_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer),
|
||||
INT64_FORMAT "ms", java_millis() - _vm_start_time_millis);
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char * LogDecorations::create_timenanos_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::javaTimeNanos());
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char * LogDecorations::create_uptimenanos_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), INT64_FORMAT "ns", os::elapsed_counter());
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char * LogDecorations::create_pid_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%d", os::current_process_id());
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char * LogDecorations::create_tid_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer),
|
||||
INTX_FORMAT, Thread::current()->osthread()->thread_id());
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char* LogDecorations::create_level_decoration(char* pos) {
|
||||
int written = jio_snprintf(pos, DecorationsBufferSize - (pos - _decorations_buffer), "%s", LogLevel::name(_level));
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
||||
|
||||
char* LogDecorations::create_tags_decoration(char* pos) {
|
||||
int written = _tagset.label(pos, DecorationsBufferSize - (pos - _decorations_buffer));
|
||||
ASSERT_AND_RETURN(written, pos)
|
||||
}
|
62
hotspot/src/share/vm/logging/logDecorations.hpp
Normal file
62
hotspot/src/share/vm/logging/logDecorations.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGDECORATIONS_HPP
|
||||
#define SHARE_VM_LOGGING_LOGDECORATIONS_HPP
|
||||
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
// Temporary object containing the necessary data for a log call's decorations (timestamps, etc).
|
||||
class LogDecorations VALUE_OBJ_CLASS_SPEC {
|
||||
public:
|
||||
static const int DecorationsBufferSize = 256;
|
||||
private:
|
||||
char _decorations_buffer[DecorationsBufferSize];
|
||||
char* _decoration_offset[LogDecorators::Count];
|
||||
LogLevelType _level;
|
||||
LogTagSet _tagset;
|
||||
jlong _millis;
|
||||
static jlong _vm_start_time_millis;
|
||||
|
||||
jlong java_millis();
|
||||
void create_decorations(const LogDecorators& decorators);
|
||||
|
||||
#define DECORATOR(name, abbr) char* create_##name##_decoration(char* pos);
|
||||
DECORATOR_LIST
|
||||
#undef DECORATOR
|
||||
|
||||
public:
|
||||
LogDecorations(LogLevelType level, const LogTagSet& tagset, const LogDecorators& decorators);
|
||||
|
||||
const char* decoration(LogDecorators::Decorator decorator) const {
|
||||
return _decoration_offset[decorator];
|
||||
}
|
||||
|
||||
static void set_vm_start_time_millis(jlong start_time) {
|
||||
_vm_start_time_millis = start_time;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGDECORATIONS_HPP
|
81
hotspot/src/share/vm/logging/logDecorators.cpp
Normal file
81
hotspot/src/share/vm/logging/logDecorators.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
|
||||
const char* LogDecorators::_name[][2] = {
|
||||
#define DECORATOR(n, a) {#n, #a},
|
||||
DECORATOR_LIST
|
||||
#undef DECORATOR
|
||||
};
|
||||
|
||||
LogDecorators::Decorator LogDecorators::from_string(const char* str) {
|
||||
for (size_t i = 0; i < Count; i++) {
|
||||
Decorator d = static_cast<Decorator>(i);
|
||||
if (strcasecmp(str, name(d)) == 0 || strcasecmp(str, abbreviation(d)) == 0) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
bool LogDecorators::parse(const char* decorator_args, outputStream* errstream) {
|
||||
if (decorator_args == NULL || strlen(decorator_args) == 0) {
|
||||
_decorators = DefaultDecoratorsMask;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strcasecmp(decorator_args, "none") == 0 ) {
|
||||
_decorators = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
uint tmp_decorators = 0;
|
||||
char* args_copy = os::strdup_check_oom(decorator_args, mtLogging);
|
||||
char* token = args_copy;
|
||||
char* comma_pos;
|
||||
do {
|
||||
comma_pos = strchr(token, ',');
|
||||
if (comma_pos != NULL) {
|
||||
*comma_pos = '\0';
|
||||
}
|
||||
Decorator d = from_string(token);
|
||||
if (d == Invalid) {
|
||||
if (errstream != NULL) {
|
||||
errstream->print_cr("Invalid decorator '%s'.", token);
|
||||
}
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
tmp_decorators |= mask(d);
|
||||
token = comma_pos + 1;
|
||||
} while (comma_pos != NULL);
|
||||
os::free(args_copy);
|
||||
if (result) {
|
||||
_decorators = tmp_decorators;
|
||||
}
|
||||
return result;
|
||||
}
|
105
hotspot/src/share/vm/logging/logDecorators.hpp
Normal file
105
hotspot/src/share/vm/logging/logDecorators.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGDECORATORS_HPP
|
||||
#define SHARE_VM_LOGGING_LOGDECORATORS_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
// The list of available decorators:
|
||||
// time - Current time and date in ISO-8601 format
|
||||
// uptime - Time since the start of the JVM in seconds and milliseconds (e.g., 6.567s)
|
||||
// timemillis - The same value as generated by System.currentTimeMillis()
|
||||
// uptimemillis - Milliseconds since the JVM started
|
||||
// timenanos - The same value as generated by System.nanoTime()
|
||||
// uptimenanos - Nanoseconds since the JVM started
|
||||
// pid - The process identifier
|
||||
// tid - The thread identifier
|
||||
// level - The level associated with the log message
|
||||
// tags - The tag-set associated with the log message
|
||||
#define DECORATOR_LIST \
|
||||
DECORATOR(time, t) \
|
||||
DECORATOR(uptime, u) \
|
||||
DECORATOR(timemillis, tm) \
|
||||
DECORATOR(uptimemillis, um) \
|
||||
DECORATOR(timenanos, tn) \
|
||||
DECORATOR(uptimenanos, un) \
|
||||
DECORATOR(pid, p) \
|
||||
DECORATOR(tid, ti) \
|
||||
DECORATOR(level, l) \
|
||||
DECORATOR(tags, tg)
|
||||
|
||||
// LogDecorators represents a selection of decorators that should be prepended to
|
||||
// each log message for a given output. Decorators are always prepended in the order
|
||||
// declared above. For example, logging with 'uptime, level, tags' decorators results in:
|
||||
// [0,943s][info ][logging] message.
|
||||
class LogDecorators VALUE_OBJ_CLASS_SPEC {
|
||||
public:
|
||||
enum Decorator {
|
||||
#define DECORATOR(name, abbr) name##_decorator,
|
||||
DECORATOR_LIST
|
||||
#undef DECORATOR
|
||||
Count,
|
||||
Invalid
|
||||
};
|
||||
|
||||
private:
|
||||
uint _decorators;
|
||||
static const char* _name[][2];
|
||||
static const uint DefaultDecoratorsMask = (1 << uptime_decorator) | (1 << level_decorator) | (1 << tags_decorator);
|
||||
|
||||
static uint mask(LogDecorators::Decorator decorator) {
|
||||
return 1 << decorator;
|
||||
}
|
||||
|
||||
public:
|
||||
LogDecorators() : _decorators(DefaultDecoratorsMask) {
|
||||
};
|
||||
|
||||
void clear() {
|
||||
_decorators = 0;
|
||||
}
|
||||
|
||||
static const char* name(LogDecorators::Decorator decorator) {
|
||||
return _name[decorator][0];
|
||||
}
|
||||
|
||||
static const char* abbreviation(LogDecorators::Decorator decorator) {
|
||||
return _name[decorator][1];
|
||||
}
|
||||
|
||||
static LogDecorators::Decorator from_string(const char* str);
|
||||
|
||||
void combine_with(const LogDecorators &source) {
|
||||
_decorators |= source._decorators;
|
||||
}
|
||||
|
||||
bool is_decorator(LogDecorators::Decorator decorator) const {
|
||||
return (_decorators & mask(decorator)) != 0;
|
||||
}
|
||||
|
||||
bool parse(const char* decorator_args, outputStream* errstream = NULL);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGDECORATORS_HPP
|
94
hotspot/src/share/vm/logging/logDiagnosticCommand.cpp
Normal file
94
hotspot/src/share/vm/logging/logDiagnosticCommand.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logDiagnosticCommand.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
LogDiagnosticCommand::LogDiagnosticCommand(outputStream* output, bool heap_allocated)
|
||||
: DCmdWithParser(output, heap_allocated),
|
||||
_output("output", "The name or index (#<index>) of output to configure.", "STRING", false),
|
||||
_output_options("output_options", "Options for the output.", "STRING", false),
|
||||
_what("what", "Configures what tags to log.", "STRING", false),
|
||||
_decorators("decorators", "Configures which decorators to use. Use 'none' or an empty value to remove all.", "STRING", false),
|
||||
_disable("disable", "Turns off all logging and clears the log configuration.", "BOOLEAN", false),
|
||||
_list("list", "Lists current log configuration.", "BOOLEAN", false) {
|
||||
_dcmdparser.add_dcmd_option(&_output);
|
||||
_dcmdparser.add_dcmd_option(&_output_options);
|
||||
_dcmdparser.add_dcmd_option(&_what);
|
||||
_dcmdparser.add_dcmd_option(&_decorators);
|
||||
_dcmdparser.add_dcmd_option(&_disable);
|
||||
_dcmdparser.add_dcmd_option(&_list);
|
||||
}
|
||||
|
||||
int LogDiagnosticCommand::num_arguments() {
|
||||
ResourceMark rm;
|
||||
LogDiagnosticCommand* dcmd = new LogDiagnosticCommand(NULL, false);
|
||||
if (dcmd != NULL) {
|
||||
DCmdMark mark(dcmd);
|
||||
return dcmd->_dcmdparser.num_arguments();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void LogDiagnosticCommand::registerCommand() {
|
||||
uint32_t full_visibility = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean;
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<LogDiagnosticCommand>(full_visibility, true, false));
|
||||
}
|
||||
|
||||
void LogDiagnosticCommand::execute(DCmdSource source, TRAPS) {
|
||||
bool any_command = false;
|
||||
if (_disable.has_value()) {
|
||||
MutexLocker ml(LogConfiguration_lock);
|
||||
LogConfiguration::disable_logging();
|
||||
any_command = true;
|
||||
}
|
||||
|
||||
if (_output.has_value() || _what.has_value() || _decorators.has_value()) {
|
||||
MutexLocker ml(LogConfiguration_lock);
|
||||
if (!LogConfiguration::parse_log_arguments(_output.value(),
|
||||
_what.value(),
|
||||
_decorators.value(),
|
||||
_output_options.value(),
|
||||
output())) {
|
||||
return;
|
||||
}
|
||||
any_command = true;
|
||||
}
|
||||
|
||||
if (_list.has_value()) {
|
||||
MutexLocker ml(LogConfiguration_lock);
|
||||
LogConfiguration::describe(output());
|
||||
any_command = true;
|
||||
}
|
||||
|
||||
if (!any_command) {
|
||||
// If no argument was provided, print usage
|
||||
print_help(LogDiagnosticCommand::name());
|
||||
}
|
||||
|
||||
}
|
68
hotspot/src/share/vm/logging/logDiagnosticCommand.hpp
Normal file
68
hotspot/src/share/vm/logging/logDiagnosticCommand.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP
|
||||
#define SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP
|
||||
|
||||
#include "services/diagnosticCommand.hpp"
|
||||
|
||||
// The LogDiagnosticCommand represents the 'VM.log' DCMD
|
||||
// that allows configuration of the logging at runtime.
|
||||
// It can be used to view or modify the current log configuration.
|
||||
// VM.log without additional arguments prints the usage description.
|
||||
// The 'list' argument will list all available log tags,
|
||||
// levels, decorators and currently configured log outputs.
|
||||
// Specifying 'disable' will disable logging completely.
|
||||
// The remaining arguments are used to set a log output to log everything
|
||||
// with the specified tags and levels using the given decorators.
|
||||
class LogDiagnosticCommand : public DCmdWithParser {
|
||||
protected:
|
||||
DCmdArgument<char *> _output;
|
||||
DCmdArgument<char *> _output_options;
|
||||
DCmdArgument<char *> _what;
|
||||
DCmdArgument<char *> _decorators;
|
||||
DCmdArgument<bool> _disable;
|
||||
DCmdArgument<bool> _list;
|
||||
|
||||
public:
|
||||
LogDiagnosticCommand(outputStream* output, bool heap_allocated);
|
||||
void execute(DCmdSource source, TRAPS);
|
||||
static void registerCommand();
|
||||
static int num_arguments();
|
||||
|
||||
static const char* name() {
|
||||
return "VM.log";
|
||||
}
|
||||
|
||||
static const char* description() {
|
||||
return "Lists, enables, disables or changes a log output configuration.";
|
||||
}
|
||||
|
||||
// Used by SecurityManager. This DCMD requires ManagementPermission = control.
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission", "control", NULL};
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGDIAGNOSTICCOMMAND_HPP
|
283
hotspot/src/share/vm/logging/logFileOutput.cpp
Normal file
283
hotspot/src/share/vm/logging/logFileOutput.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logFileOutput.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
|
||||
const char* LogFileOutput::FileOpenMode = "a";
|
||||
const char* LogFileOutput::PidFilenamePlaceholder = "%p";
|
||||
const char* LogFileOutput::TimestampFilenamePlaceholder = "%t";
|
||||
const char* LogFileOutput::TimestampFormat = "%Y-%m-%d_%H-%M-%S";
|
||||
const char* LogFileOutput::FileSizeOptionKey = "filesize";
|
||||
const char* LogFileOutput::FileCountOptionKey = "filecount";
|
||||
char LogFileOutput::_pid_str[PidBufferSize];
|
||||
char LogFileOutput::_vm_start_time_str[StartTimeBufferSize];
|
||||
|
||||
LogFileOutput::LogFileOutput(const char* name)
|
||||
: LogFileStreamOutput(NULL), _name(os::strdup_check_oom(name, mtLogging)),
|
||||
_file_name(NULL), _archive_name(NULL), _archive_name_len(0), _current_size(0),
|
||||
_rotate_size(0), _current_file(1), _file_count(0),
|
||||
_rotation_lock(Mutex::leaf, "LogFileOutput rotation lock", true, Mutex::_safepoint_check_sometimes) {
|
||||
_file_name = make_file_name(name, _pid_str, _vm_start_time_str);
|
||||
}
|
||||
|
||||
void LogFileOutput::set_file_name_parameters(jlong vm_start_time) {
|
||||
int res = jio_snprintf(_pid_str, sizeof(_pid_str), "%d", os::current_process_id());
|
||||
assert(res > 0, "PID buffer too small");
|
||||
|
||||
struct tm local_time;
|
||||
time_t utc_time = vm_start_time / 1000;
|
||||
os::localtime_pd(&utc_time, &local_time);
|
||||
res = (int)strftime(_vm_start_time_str, sizeof(_vm_start_time_str), TimestampFormat, &local_time);
|
||||
assert(res > 0, "VM start time buffer too small.");
|
||||
}
|
||||
|
||||
LogFileOutput::~LogFileOutput() {
|
||||
if (_stream != NULL) {
|
||||
if (_archive_name != NULL) {
|
||||
archive();
|
||||
}
|
||||
if (fclose(_stream) != 0) {
|
||||
jio_fprintf(defaultStream::error_stream(), "Could not close log file '%s' (%s).\n",
|
||||
_file_name, strerror(errno));
|
||||
}
|
||||
}
|
||||
os::free(_archive_name);
|
||||
os::free(_file_name);
|
||||
os::free(const_cast<char*>(_name));
|
||||
}
|
||||
|
||||
size_t LogFileOutput::parse_value(const char* value_str) {
|
||||
char* end;
|
||||
unsigned long long value = strtoull(value_str, &end, 10);
|
||||
if (!isdigit(*value_str) || end != value_str + strlen(value_str) || value >= SIZE_MAX) {
|
||||
return SIZE_MAX;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool LogFileOutput::configure_rotation(const char* options) {
|
||||
if (options == NULL || strlen(options) == 0) {
|
||||
return true;
|
||||
}
|
||||
bool success = true;
|
||||
char* opts = os::strdup_check_oom(options, mtLogging);
|
||||
|
||||
char* comma_pos;
|
||||
char* pos = opts;
|
||||
do {
|
||||
comma_pos = strchr(pos, ',');
|
||||
if (comma_pos != NULL) {
|
||||
*comma_pos = '\0';
|
||||
}
|
||||
|
||||
char* equals_pos = strchr(pos, '=');
|
||||
if (equals_pos == NULL) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
char* key = pos;
|
||||
char* value_str = equals_pos + 1;
|
||||
*equals_pos = '\0';
|
||||
|
||||
if (strcmp(FileCountOptionKey, key) == 0) {
|
||||
size_t value = parse_value(value_str);
|
||||
if (value == SIZE_MAX || value >= UINT_MAX) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
_file_count = static_cast<uint>(value);
|
||||
_file_count_max_digits = static_cast<uint>(log10(static_cast<double>(_file_count)) + 1);
|
||||
_archive_name_len = 2 + strlen(_file_name) + _file_count_max_digits;
|
||||
_archive_name = NEW_C_HEAP_ARRAY(char, _archive_name_len, mtLogging);
|
||||
} else if (strcmp(FileSizeOptionKey, key) == 0) {
|
||||
size_t value = parse_value(value_str);
|
||||
if (value == SIZE_MAX || value > SIZE_MAX / K) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
_rotate_size = value * K;
|
||||
} else {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
pos = comma_pos + 1;
|
||||
} while (comma_pos != NULL);
|
||||
|
||||
os::free(opts);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool LogFileOutput::initialize(const char* options) {
|
||||
if (!configure_rotation(options)) {
|
||||
return false;
|
||||
}
|
||||
_stream = fopen(_file_name, FileOpenMode);
|
||||
if (_stream == NULL) {
|
||||
log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int LogFileOutput::write(const LogDecorations& decorations, const char* msg) {
|
||||
if (_stream == NULL) {
|
||||
// An error has occurred with this output, avoid writing to it.
|
||||
return 0;
|
||||
}
|
||||
int written = LogFileStreamOutput::write(decorations, msg);
|
||||
_current_size += written;
|
||||
|
||||
if (should_rotate()) {
|
||||
MutexLockerEx ml(&_rotation_lock, true /* no safepoint check */);
|
||||
if (should_rotate()) {
|
||||
rotate();
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
void LogFileOutput::archive() {
|
||||
assert(_archive_name != NULL && _archive_name_len > 0, "Rotation must be configured before using this function.");
|
||||
int ret = jio_snprintf(_archive_name, _archive_name_len, "%s.%0*u",
|
||||
_file_name, _file_count_max_digits, _current_file);
|
||||
assert(ret >= 0, "Buffer should always be large enough");
|
||||
|
||||
// Attempt to remove possibly existing archived log file before we rename.
|
||||
// Don't care if it fails, we really only care about the rename that follows.
|
||||
remove(_archive_name);
|
||||
|
||||
// Rename the file from ex hotspot.log to hotspot.log.2
|
||||
if (rename(_file_name, _archive_name) == -1) {
|
||||
jio_fprintf(defaultStream::error_stream(), "Could not rename log file '%s' to '%s' (%s).\n",
|
||||
_file_name, _archive_name, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void LogFileOutput::rotate() {
|
||||
// Archive the current log file
|
||||
archive();
|
||||
|
||||
// Open the active log file using the same stream as before
|
||||
_stream = freopen(_file_name, FileOpenMode, _stream);
|
||||
if (_stream == NULL) {
|
||||
jio_fprintf(defaultStream::error_stream(), "Could not reopen file '%s' during log rotation (%s).\n",
|
||||
_file_name, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset accumulated size, increase current file counter, and check for file count wrap-around.
|
||||
_current_size = 0;
|
||||
_current_file = (_current_file >= _file_count ? 1 : _current_file + 1);
|
||||
}
|
||||
|
||||
char* LogFileOutput::make_file_name(const char* file_name,
|
||||
const char* pid_string,
|
||||
const char* timestamp_string) {
|
||||
char* result = NULL;
|
||||
|
||||
// Lets start finding out if we have any %d and/or %t in the name.
|
||||
// We will only replace the first occurrence of any placeholder
|
||||
const char* pid = strstr(file_name, PidFilenamePlaceholder);
|
||||
const char* timestamp = strstr(file_name, TimestampFilenamePlaceholder);
|
||||
|
||||
if (pid == NULL && timestamp == NULL) {
|
||||
// We found no place-holders, return the simple filename
|
||||
return os::strdup_check_oom(file_name, mtLogging);
|
||||
}
|
||||
|
||||
// At least one of the place-holders were found in the file_name
|
||||
const char* first = "";
|
||||
size_t first_pos = -1;
|
||||
size_t first_replace_len = 0;
|
||||
|
||||
const char* second = "";
|
||||
size_t second_pos = -1;
|
||||
size_t second_replace_len = 0;
|
||||
|
||||
// If we found a %p, then setup our variables accordingly
|
||||
if (pid != NULL) {
|
||||
if (timestamp == NULL || pid < timestamp) {
|
||||
first = pid_string;
|
||||
first_pos = pid - file_name;
|
||||
first_replace_len = strlen(PidFilenamePlaceholder);
|
||||
} else {
|
||||
second = pid_string;
|
||||
second_pos = pid - file_name;
|
||||
second_replace_len = strlen(PidFilenamePlaceholder);
|
||||
}
|
||||
}
|
||||
|
||||
if (timestamp != NULL) {
|
||||
if (pid == NULL || timestamp < pid) {
|
||||
first = timestamp_string;
|
||||
first_pos = timestamp - file_name;
|
||||
first_replace_len = strlen(TimestampFilenamePlaceholder);
|
||||
} else {
|
||||
second = timestamp_string;
|
||||
second_pos = timestamp - file_name;
|
||||
second_replace_len = strlen(TimestampFilenamePlaceholder);
|
||||
}
|
||||
}
|
||||
|
||||
size_t first_len = strlen(first);
|
||||
size_t second_len = strlen(second);
|
||||
|
||||
// Allocate the new buffer, size it to hold all we want to put in there +1.
|
||||
size_t result_len = strlen(file_name) + first_len - first_replace_len + second_len - second_replace_len;
|
||||
result = NEW_C_HEAP_ARRAY(char, result_len + 1, mtLogging);
|
||||
|
||||
// Assemble the strings
|
||||
size_t file_name_pos = 0;
|
||||
size_t i = 0;
|
||||
while (i < result_len) {
|
||||
if (file_name_pos == first_pos) {
|
||||
// We are in the range of the first placeholder
|
||||
strcpy(result + i, first);
|
||||
// Bump output buffer position with length of replacing string
|
||||
i += first_len;
|
||||
// Bump source buffer position to skip placeholder
|
||||
file_name_pos += first_replace_len;
|
||||
} else if (file_name_pos == second_pos) {
|
||||
// We are in the range of the second placeholder
|
||||
strcpy(result + i, second);
|
||||
i += second_len;
|
||||
file_name_pos += second_replace_len;
|
||||
} else {
|
||||
// Else, copy char by char of the original file
|
||||
result[i] = file_name[file_name_pos++];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// Add terminating char
|
||||
result[result_len] = '\0';
|
||||
return result;
|
||||
}
|
83
hotspot/src/share/vm/logging/logFileOutput.hpp
Normal file
83
hotspot/src/share/vm/logging/logFileOutput.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP
|
||||
#define SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP
|
||||
|
||||
#include "logging/logFileStreamOutput.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogDecorations;
|
||||
|
||||
// The log file output, with support for file rotation based on a target size.
|
||||
class LogFileOutput : public LogFileStreamOutput {
|
||||
private:
|
||||
static const char* FileOpenMode;
|
||||
static const char* FileCountOptionKey;
|
||||
static const char* FileSizeOptionKey;
|
||||
static const char* PidFilenamePlaceholder;
|
||||
static const char* TimestampFilenamePlaceholder;
|
||||
static const char* TimestampFormat;
|
||||
static const size_t StartTimeBufferSize = 20;
|
||||
static const size_t PidBufferSize = 21;
|
||||
static char _pid_str[PidBufferSize];
|
||||
static char _vm_start_time_str[StartTimeBufferSize];
|
||||
|
||||
Mutex _rotation_lock;
|
||||
const char* _name;
|
||||
char* _file_name;
|
||||
char* _archive_name;
|
||||
|
||||
uint _current_file;
|
||||
uint _file_count;
|
||||
uint _file_count_max_digits;
|
||||
|
||||
size_t _archive_name_len;
|
||||
size_t _rotate_size;
|
||||
size_t _current_size;
|
||||
|
||||
void archive();
|
||||
void rotate();
|
||||
bool configure_rotation(const char* options);
|
||||
char *make_file_name(const char* file_name, const char* pid_string, const char* timestamp_string);
|
||||
static size_t parse_value(const char* value_str);
|
||||
|
||||
bool should_rotate() const {
|
||||
return _file_count > 0 && _rotate_size > 0 && _current_size >= _rotate_size;
|
||||
}
|
||||
|
||||
public:
|
||||
LogFileOutput(const char *name);
|
||||
virtual ~LogFileOutput();
|
||||
virtual bool initialize(const char* options);
|
||||
virtual int write(const LogDecorations& decorations, const char* msg);
|
||||
|
||||
virtual const char* name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
static void set_file_name_parameters(jlong start_time);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGFILEOUTPUT_HPP
|
62
hotspot/src/share/vm/logging/logFileStreamOutput.cpp
Normal file
62
hotspot/src/share/vm/logging/logFileStreamOutput.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "logging/logDecorations.hpp"
|
||||
#include "logging/logFileStreamOutput.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
|
||||
LogStdoutOutput LogStdoutOutput::_instance;
|
||||
LogStderrOutput LogStderrOutput::_instance;
|
||||
|
||||
int LogFileStreamOutput::write(const LogDecorations& decorations, const char* msg) {
|
||||
char decoration_buf[LogDecorations::DecorationsBufferSize];
|
||||
char* position = decoration_buf;
|
||||
int total_written = 0;
|
||||
|
||||
for (uint i = 0; i < LogDecorators::Count; i++) {
|
||||
LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(i);
|
||||
if (!_decorators.is_decorator(decorator)) {
|
||||
continue;
|
||||
}
|
||||
int written = jio_snprintf(position, sizeof(decoration_buf) - total_written, "[%-*s]",
|
||||
_decorator_padding[decorator],
|
||||
decorations.decoration(decorator));
|
||||
if (written <= 0) {
|
||||
return -1;
|
||||
} else if (static_cast<size_t>(written - 2) > _decorator_padding[decorator]) {
|
||||
_decorator_padding[decorator] = written - 2;
|
||||
}
|
||||
position += written;
|
||||
total_written += written;
|
||||
}
|
||||
|
||||
if (total_written == 0) {
|
||||
total_written = jio_fprintf(_stream, "%s\n", msg);
|
||||
} else {
|
||||
total_written = jio_fprintf(_stream, "%s %s\n", decoration_buf, msg);
|
||||
}
|
||||
fflush(_stream);
|
||||
return total_written;
|
||||
}
|
82
hotspot/src/share/vm/logging/logFileStreamOutput.hpp
Normal file
82
hotspot/src/share/vm/logging/logFileStreamOutput.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP
|
||||
#define SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP
|
||||
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogDecorations;
|
||||
|
||||
// Base class for all FileStream-based log outputs.
|
||||
class LogFileStreamOutput : public LogOutput {
|
||||
protected:
|
||||
FILE* _stream;
|
||||
size_t _decorator_padding[LogDecorators::Count];
|
||||
|
||||
LogFileStreamOutput(FILE *stream) : _stream(stream) {
|
||||
for (size_t i = 0; i < LogDecorators::Count; i++) {
|
||||
_decorator_padding[i] = 0;
|
||||
}
|
||||
_decorator_padding[LogDecorators::level_decorator] = 7;
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int write(const LogDecorations &decorations, const char* msg);
|
||||
};
|
||||
|
||||
class LogStdoutOutput : public LogFileStreamOutput {
|
||||
friend class LogOutput;
|
||||
private:
|
||||
static LogStdoutOutput _instance;
|
||||
LogStdoutOutput() : LogFileStreamOutput(stdout) {
|
||||
set_config_string("all=off");
|
||||
}
|
||||
virtual bool initialize(const char* options) {
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
virtual const char* name() const {
|
||||
return "stdout";
|
||||
}
|
||||
};
|
||||
|
||||
class LogStderrOutput : public LogFileStreamOutput {
|
||||
friend class LogOutput;
|
||||
private:
|
||||
static LogStderrOutput _instance;
|
||||
LogStderrOutput() : LogFileStreamOutput(stderr) {
|
||||
set_config_string("all=warning");
|
||||
}
|
||||
virtual bool initialize(const char* options) {
|
||||
return false;
|
||||
}
|
||||
public:
|
||||
virtual const char* name() const {
|
||||
return "stderr";
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGFILESTREAMOUTPUT_HPP
|
42
hotspot/src/share/vm/logging/logLevel.cpp
Normal file
42
hotspot/src/share/vm/logging/logLevel.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
const char* LogLevel::_name[] = {
|
||||
"off",
|
||||
#define LOG_LEVEL(name, printname) #printname,
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
};
|
||||
|
||||
LogLevelType LogLevel::from_string(const char* str) {
|
||||
for (uint i = 0; i < Count; i++) {
|
||||
if (strcasecmp(str, _name[i]) == 0) {
|
||||
return static_cast<LogLevelType>(i);
|
||||
}
|
||||
}
|
||||
return Invalid;
|
||||
}
|
86
hotspot/src/share/vm/logging/logLevel.hpp
Normal file
86
hotspot/src/share/vm/logging/logLevel.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGLEVEL_HPP
|
||||
#define SHARE_VM_LOGGING_LOGLEVEL_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// The list of log levels:
|
||||
//
|
||||
// develop - A non-product level that is finer than trace.
|
||||
// Should be used for really expensive and/or
|
||||
// extensive logging, or logging that shouldn't
|
||||
// or can't be included in a product build.
|
||||
//
|
||||
// trace - Finest level of logging in product builds.
|
||||
// Use for extensive/noisy logging that can
|
||||
// give slow-down when enabled.
|
||||
//
|
||||
// debug - A finer level of logging. Use for semi-noisy
|
||||
// logging that is does not fit the info level.
|
||||
//
|
||||
// info - General level of logging. Use for significant
|
||||
// events and/or informative summaries.
|
||||
//
|
||||
// warning - Important messages that are not strictly errors.
|
||||
//
|
||||
// error - Critical messages caused by errors.
|
||||
//
|
||||
#define LOG_LEVEL_LIST \
|
||||
NOT_PRODUCT(LOG_LEVEL(Develop, develop)) \
|
||||
LOG_LEVEL(Trace, trace) \
|
||||
LOG_LEVEL(Debug, debug) \
|
||||
LOG_LEVEL(Info, info) \
|
||||
LOG_LEVEL(Warning, warning) \
|
||||
LOG_LEVEL(Error, error)
|
||||
|
||||
class LogLevel : public AllStatic {
|
||||
public:
|
||||
enum type {
|
||||
Off,
|
||||
#define LOG_LEVEL(name, printname) name,
|
||||
LOG_LEVEL_LIST
|
||||
#undef LOG_LEVEL
|
||||
Count,
|
||||
Invalid,
|
||||
First = Off + 1,
|
||||
Last = Error,
|
||||
Default = Warning,
|
||||
Unspecified = Info
|
||||
};
|
||||
|
||||
static const char *name(LogLevel::type level) {
|
||||
return _name[level];
|
||||
}
|
||||
|
||||
static LogLevel::type from_string(const char* str);
|
||||
|
||||
private:
|
||||
static const char* _name[];
|
||||
};
|
||||
|
||||
typedef LogLevel::type LogLevelType;
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGLEVEL_HPP
|
40
hotspot/src/share/vm/logging/logOutput.cpp
Normal file
40
hotspot/src/share/vm/logging/logOutput.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logFileStreamOutput.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
|
||||
LogOutput* const LogOutput::Stdout = &LogStdoutOutput::_instance;
|
||||
LogOutput* const LogOutput::Stderr = &LogStderrOutput::_instance;
|
||||
|
||||
LogOutput::~LogOutput() {
|
||||
os::free(_config_string);
|
||||
}
|
||||
|
||||
void LogOutput::set_config_string(const char* string) {
|
||||
os::free(_config_string);
|
||||
_config_string = os::strdup_check_oom(string, mtLogging);
|
||||
}
|
68
hotspot/src/share/vm/logging/logOutput.hpp
Normal file
68
hotspot/src/share/vm/logging/logOutput.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGOUTPUT_HPP
|
||||
#define SHARE_VM_LOGGING_LOGOUTPUT_HPP
|
||||
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogDecorations;
|
||||
|
||||
// The base class/interface for log outputs.
|
||||
// Keeps track of the latest configuration string,
|
||||
// and its selected decorators.
|
||||
class LogOutput : public CHeapObj<mtLogging> {
|
||||
protected:
|
||||
LogDecorators _decorators;
|
||||
char* _config_string;
|
||||
|
||||
public:
|
||||
static LogOutput* const Stdout;
|
||||
static LogOutput* const Stderr;
|
||||
|
||||
void set_decorators(const LogDecorators &decorators) {
|
||||
_decorators = decorators;
|
||||
}
|
||||
|
||||
const LogDecorators& decorators() const {
|
||||
return _decorators;
|
||||
}
|
||||
|
||||
const char* config_string() const {
|
||||
return _config_string;
|
||||
}
|
||||
|
||||
LogOutput() : _config_string(NULL) {
|
||||
}
|
||||
|
||||
virtual ~LogOutput();
|
||||
void set_config_string(const char* string);
|
||||
|
||||
virtual const char* name() const = 0;
|
||||
virtual bool initialize(const char* options) = 0;
|
||||
virtual int write(const LogDecorations &decorations, const char* msg) = 0;
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGOUTPUT_HPP
|
128
hotspot/src/share/vm/logging/logOutputList.cpp
Normal file
128
hotspot/src/share/vm/logging/logOutputList.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logOutputList.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/atomic.inline.hpp"
|
||||
#include "runtime/orderAccess.inline.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
jint LogOutputList::increase_readers() {
|
||||
jint result = Atomic::add(1, &_active_readers);
|
||||
assert(_active_readers > 0, "Ensure we have consistent state");
|
||||
return result;
|
||||
}
|
||||
|
||||
jint LogOutputList::decrease_readers() {
|
||||
jint result = Atomic::add(-1, &_active_readers);
|
||||
assert(result >= 0, "Ensure we have consistent state");
|
||||
return result;
|
||||
}
|
||||
|
||||
void LogOutputList::wait_until_no_readers() const {
|
||||
OrderAccess::storeload();
|
||||
while (_active_readers != 0) {
|
||||
// Busy wait
|
||||
}
|
||||
}
|
||||
|
||||
void LogOutputList::set_output_level(LogOutput* output, LogLevelType level) {
|
||||
LogOutputNode* node = find(output);
|
||||
if (level == LogLevel::Off && node != NULL) {
|
||||
remove_output(node);
|
||||
} else if (level != LogLevel::Off && node == NULL) {
|
||||
add_output(output, level);
|
||||
} else if (node != NULL) {
|
||||
update_output_level(node, level);
|
||||
}
|
||||
}
|
||||
|
||||
LogOutputList::LogOutputNode* LogOutputList::find(LogOutput* output) {
|
||||
for (LogOutputNode* node = _level_start[LogLevel::Last]; node != NULL; node = node->_next) {
|
||||
if (output == node->_value) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void LogOutputList::remove_output(LogOutputList::LogOutputNode* node) {
|
||||
assert(node != NULL, "Node must be non-null");
|
||||
|
||||
// Remove node from _level_start first
|
||||
bool found = false;
|
||||
for (uint level = LogLevel::First; level < LogLevel::Count; level++) {
|
||||
if (_level_start[level] == node) {
|
||||
found = true;
|
||||
_level_start[level] = node->_next;
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove it from the linked list
|
||||
for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) {
|
||||
if (cur->_next == node) {
|
||||
found = true;
|
||||
cur->_next = node->_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(found, "Node to be removed should always be found");
|
||||
|
||||
wait_until_no_readers();
|
||||
delete node;
|
||||
}
|
||||
|
||||
void LogOutputList::add_output(LogOutput* output, LogLevelType level) {
|
||||
LogOutputNode* node = new LogOutputNode();
|
||||
node->_value = output;
|
||||
node->_level = level;
|
||||
|
||||
// Set the next pointer to the first node of a lower level
|
||||
for (node->_next = _level_start[level];
|
||||
node->_next != NULL && node->_next->_level == level;
|
||||
node->_next = node->_next->_next) {
|
||||
}
|
||||
|
||||
// Update the _level_start index
|
||||
for (int l = LogLevel::Last; l >= level; l--) {
|
||||
if (_level_start[l] == NULL || _level_start[l]->_level < level) {
|
||||
_level_start[l] = node;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the node the list
|
||||
for (LogOutputNode* cur = _level_start[LogLevel::Last]; cur != NULL; cur = cur->_next) {
|
||||
if (cur != node && cur->_next == node->_next) {
|
||||
cur->_next = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LogOutputList::update_output_level(LogOutputList::LogOutputNode* node, LogLevelType level) {
|
||||
add_output(node->_value, level);
|
||||
wait_until_no_readers();
|
||||
remove_output(node);
|
||||
}
|
120
hotspot/src/share/vm/logging/logOutputList.hpp
Normal file
120
hotspot/src/share/vm/logging/logOutputList.hpp
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
|
||||
#define SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
|
||||
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogOutput;
|
||||
|
||||
// Data structure to keep track of log outputs for a given tagset.
|
||||
// Essentially a sorted linked list going from error level outputs
|
||||
// to outputs of finer levels. Keeps an index from each level to
|
||||
// the first node in the list for the corresponding level.
|
||||
// This allows a log message on, for example, info level to jump
|
||||
// straight into the list where the first info level output can
|
||||
// be found. The log message will then be printed on that output,
|
||||
// as well as all outputs in nodes that follow in the list (which
|
||||
// can be additional info level outputs and/or debug and trace outputs).
|
||||
//
|
||||
// Each instance keeps track of the number of current readers of the list.
|
||||
// To remove a node from the list the node must first be unlinked,
|
||||
// and the memory for that node can be freed whenever the removing
|
||||
// thread observes an active reader count of 0 (after unlinking it).
|
||||
class LogOutputList VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
struct LogOutputNode : public CHeapObj<mtLogging> {
|
||||
LogOutput* _value;
|
||||
LogOutputNode* _next;
|
||||
LogLevelType _level;
|
||||
};
|
||||
|
||||
LogOutputNode* _level_start[LogLevel::Count];
|
||||
volatile jint _active_readers;
|
||||
|
||||
LogOutputNode* find(LogOutput* output);
|
||||
void remove_output(LogOutputNode* node);
|
||||
void add_output(LogOutput* output, LogLevelType level);
|
||||
void update_output_level(LogOutputNode* node, LogLevelType level);
|
||||
|
||||
public:
|
||||
LogOutputList() : _active_readers(0) {
|
||||
for (size_t i = 0; i < LogLevel::Count; i++) {
|
||||
_level_start[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Test if the outputlist has an output for the given level.
|
||||
bool is_level(LogLevelType level) {
|
||||
return _level_start[level] != NULL;
|
||||
}
|
||||
|
||||
// Set (add/update/remove) the output to the specified level.
|
||||
void set_output_level(LogOutput* output, LogLevelType level);
|
||||
|
||||
// Bookkeeping functions to keep track of number of active readers/iterators for the list.
|
||||
jint increase_readers();
|
||||
jint decrease_readers();
|
||||
void wait_until_no_readers() const;
|
||||
|
||||
class Iterator VALUE_OBJ_CLASS_SPEC {
|
||||
friend class LogOutputList;
|
||||
private:
|
||||
LogOutputNode* _current;
|
||||
LogOutputList* _list;
|
||||
Iterator(LogOutputList* list, LogOutputNode* start) : _current(start), _list(list) {
|
||||
}
|
||||
|
||||
public:
|
||||
~Iterator() {
|
||||
_list->decrease_readers();
|
||||
}
|
||||
|
||||
LogOutput* operator*() {
|
||||
return _current->_value;
|
||||
}
|
||||
|
||||
void operator++(int) {
|
||||
_current = _current->_next;
|
||||
}
|
||||
|
||||
bool operator!=(const LogOutputNode *ref) const {
|
||||
return _current != ref;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator iterator(LogLevelType level = LogLevel::Last) {
|
||||
increase_readers();
|
||||
return Iterator(this, _level_start[level]);
|
||||
}
|
||||
|
||||
LogOutputNode* end() const {
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
|
59
hotspot/src/share/vm/logging/logPrefix.hpp
Normal file
59
hotspot/src/share/vm/logging/logPrefix.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGPREFIX_HPP
|
||||
#define SHARE_VM_LOGGING_LOGPREFIX_HPP
|
||||
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
|
||||
// Prefixes prepend each log message for a specified tagset with the given prefix.
|
||||
// A prefix consists of a format string and a value or callback. Prefixes are added
|
||||
// after the decorations but before the log message.
|
||||
//
|
||||
// List of prefixes for specific tags and/or tagsets.
|
||||
// Syntax: LOG_PREFIX(<printf format>, <value/callback for value>, LOG_TAGS(<chosen log tags>))
|
||||
#define LOG_PREFIX_LIST // Currently unused/empty
|
||||
|
||||
// The empty prefix, used when there's no prefix defined.
|
||||
template <LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4, LogTagType GuardTag = LogTag::__NO_TAG>
|
||||
struct LogPrefix : public AllStatic {
|
||||
STATIC_ASSERT(GuardTag == LogTag::__NO_TAG);
|
||||
static size_t prefix(char* buf, size_t len) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#define LOG_PREFIX(fmt, fn, ...) \
|
||||
template <> struct LogPrefix<__VA_ARGS__> { \
|
||||
static size_t prefix(char* buf, size_t len) { \
|
||||
int ret = jio_snprintf(buf, len, fmt, fn); \
|
||||
assert(ret >= 0, \
|
||||
err_msg("Failed to prefix log message using prefix ('%s', '%s'), log buffer too small?", fmt, #fn)); \
|
||||
return ret; \
|
||||
} \
|
||||
};
|
||||
LOG_PREFIX_LIST
|
||||
#undef LOG_PREFIX
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGPREFIX_HPP
|
42
hotspot/src/share/vm/logging/logTag.cpp
Normal file
42
hotspot/src/share/vm/logging/logTag.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
const char* LogTag::_name[] = {
|
||||
"", // __NO_TAG
|
||||
#define LOG_TAG(name) #name,
|
||||
LOG_TAG_LIST
|
||||
#undef LOG_TAG
|
||||
};
|
||||
|
||||
LogTagType LogTag::from_string(const char* str) {
|
||||
for (uint i = 0; i < LogTag::Count; i++) {
|
||||
if (strcasecmp(str, _name[i]) == 0) {
|
||||
return static_cast<LogTagType>(i);
|
||||
}
|
||||
}
|
||||
return __NO_TAG;
|
||||
}
|
79
hotspot/src/share/vm/logging/logTag.hpp
Normal file
79
hotspot/src/share/vm/logging/logTag.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGTAG_HPP
|
||||
#define SHARE_VM_LOGGING_LOGTAG_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
// List of available logging tags. New tags should be added here.
|
||||
// (The tags 'all', 'disable' and 'help' are special tags that can
|
||||
// not be used in log calls, and should not be listed below.)
|
||||
#define LOG_TAG_LIST \
|
||||
LOG_TAG(logging)
|
||||
|
||||
#define PREFIX_LOG_TAG(T) (LogTag::T)
|
||||
|
||||
// Expand a set of log tags to their prefixed names.
|
||||
// For error detection purposes, the macro passes one more tag than what is supported.
|
||||
// If too many tags are given, a static assert in the log class will fail.
|
||||
#define LOG_TAGS_EXPANDED(T0, T1, T2, T3, T4, T5, ...) PREFIX_LOG_TAG(T0), PREFIX_LOG_TAG(T1), PREFIX_LOG_TAG(T2), \
|
||||
PREFIX_LOG_TAG(T3), PREFIX_LOG_TAG(T4), PREFIX_LOG_TAG(T5)
|
||||
// The EXPAND_VARARGS macro is required for MSVC, or it will resolve the LOG_TAGS_EXPANDED macro incorrectly.
|
||||
#define EXPAND_VARARGS(x) x
|
||||
#define LOG_TAGS(...) EXPAND_VARARGS(LOG_TAGS_EXPANDED(__VA_ARGS__, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG, __NO_TAG))
|
||||
|
||||
// Log tags are used to classify log messages.
|
||||
// Each log message can be assigned between 1 to LogTag::MaxTags number of tags.
|
||||
// Specifying multiple tags for a log message means that only outputs configured
|
||||
// for those exact tags, or a subset of the tags with a wildcard, will see the logging.
|
||||
// Multiple tags should be comma separated, e.g. log_error(tag1, tag2)("msg").
|
||||
class LogTag : public AllStatic {
|
||||
public:
|
||||
// The maximum number of tags that a single log message can have.
|
||||
// E.g. there might be hundreds of different tags available,
|
||||
// but a specific log message can only be tagged with up to MaxTags of those.
|
||||
static const size_t MaxTags = 5;
|
||||
|
||||
enum type {
|
||||
__NO_TAG,
|
||||
#define LOG_TAG(name) name,
|
||||
LOG_TAG_LIST
|
||||
#undef LOG_TAG
|
||||
Count
|
||||
};
|
||||
|
||||
static const char* name(LogTag::type tag) {
|
||||
return _name[tag];
|
||||
}
|
||||
|
||||
static LogTag::type from_string(const char *str);
|
||||
|
||||
private:
|
||||
static const char* _name[];
|
||||
};
|
||||
|
||||
typedef LogTag::type LogTagType;
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGTAG_HPP
|
160
hotspot/src/share/vm/logging/logTagLevelExpression.cpp
Normal file
160
hotspot/src/share/vm/logging/logTagLevelExpression.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logTagLevelExpression.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
|
||||
const char* LogTagLevelExpression::DefaultExpressionString = "all";
|
||||
|
||||
LogTagLevelExpression::~LogTagLevelExpression() {
|
||||
os::free(_string);
|
||||
}
|
||||
|
||||
void LogTagLevelExpression::clear() {
|
||||
_ntags = 0;
|
||||
_ncombinations = 0;
|
||||
for (size_t combination = 0; combination < MaxCombinations; combination++) {
|
||||
_level[combination] = LogLevel::Invalid;
|
||||
_allow_other_tags[combination] = false;
|
||||
for (size_t tag = 0; tag < LogTag::MaxTags; tag++) {
|
||||
_tags[combination][tag] = LogTag::__NO_TAG;
|
||||
}
|
||||
}
|
||||
os::free(_string);
|
||||
_string = NULL;
|
||||
}
|
||||
|
||||
bool LogTagLevelExpression::parse(const char* str, outputStream* errstream) {
|
||||
bool success = true;
|
||||
clear();
|
||||
if (str == NULL || strcmp(str, "") == 0) {
|
||||
str = DefaultExpressionString;
|
||||
}
|
||||
char* copy = os::strdup_check_oom(str, mtLogging);
|
||||
// Split string on commas
|
||||
for (char *comma_pos = copy, *cur = copy; success && comma_pos != NULL; cur = comma_pos + 1) {
|
||||
if (_ncombinations == MaxCombinations) {
|
||||
if (errstream != NULL) {
|
||||
errstream->print_cr("Can not have more than " SIZE_FORMAT " tag combinations in a what-expression.",
|
||||
MaxCombinations);
|
||||
}
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
comma_pos = strchr(cur, ',');
|
||||
if (comma_pos != NULL) {
|
||||
*comma_pos = '\0';
|
||||
}
|
||||
|
||||
// Parse the level, if specified
|
||||
LogLevelType level = LogLevel::Unspecified;
|
||||
char* equals = strchr(cur, '=');
|
||||
if (equals != NULL) {
|
||||
level = LogLevel::from_string(equals + 1);
|
||||
if (level == LogLevel::Invalid) {
|
||||
if (errstream != NULL) {
|
||||
errstream->print_cr("Invalid level '%s' in what-expression.", equals + 1);
|
||||
}
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
*equals = '\0'; // now ignore "=level" part of substr
|
||||
}
|
||||
set_level(level);
|
||||
|
||||
// Parse special tags such as 'all'
|
||||
if (strcmp(cur, "all") == 0) {
|
||||
set_allow_other_tags();
|
||||
new_combination();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for '*' suffix
|
||||
char* asterisk_pos = strchr(cur, '*');
|
||||
if (asterisk_pos != NULL && asterisk_pos[1] == '\0') {
|
||||
set_allow_other_tags();
|
||||
*asterisk_pos = '\0';
|
||||
}
|
||||
|
||||
// Parse the tag expression (t1+t2+...+tn)
|
||||
char* plus_pos;
|
||||
char* cur_tag = cur;
|
||||
do {
|
||||
plus_pos = strchr(cur_tag, '+');
|
||||
if (plus_pos != NULL) {
|
||||
*plus_pos = '\0';
|
||||
}
|
||||
LogTagType tag = LogTag::from_string(cur_tag);
|
||||
if (tag == LogTag::__NO_TAG) {
|
||||
if (errstream != NULL) {
|
||||
errstream->print_cr("Invalid tag '%s' in what-expression.", cur_tag);
|
||||
}
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if (_ntags == LogTag::MaxTags) {
|
||||
if (errstream != NULL) {
|
||||
errstream->print_cr("Tag combination exceeds the maximum of " SIZE_FORMAT " tags.",
|
||||
LogTag::MaxTags);
|
||||
}
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
add_tag(tag);
|
||||
cur_tag = plus_pos + 1;
|
||||
} while (plus_pos != NULL);
|
||||
|
||||
new_combination();
|
||||
}
|
||||
|
||||
// Save the (unmodified) string for printing purposes.
|
||||
_string = copy;
|
||||
strcpy(_string, str);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
LogLevelType LogTagLevelExpression::level_for(const LogTagSet& ts) const {
|
||||
LogLevelType level = LogLevel::Off;
|
||||
for (size_t combination = 0; combination < _ncombinations; combination++) {
|
||||
bool contains_all = true;
|
||||
size_t tag_idx;
|
||||
for (tag_idx = 0; tag_idx < LogTag::MaxTags && _tags[combination][tag_idx] != LogTag::__NO_TAG; tag_idx++) {
|
||||
if (!ts.contains(_tags[combination][tag_idx])) {
|
||||
contains_all = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// All tags in the expression must be part of the tagset,
|
||||
// and either the expression allows other tags (has a wildcard),
|
||||
// or the number of tags in the expression and tagset must match.
|
||||
if (contains_all && (_allow_other_tags[combination] || tag_idx == ts.ntags())) {
|
||||
level = _level[combination];
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
81
hotspot/src/share/vm/logging/logTagLevelExpression.hpp
Normal file
81
hotspot/src/share/vm/logging/logTagLevelExpression.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
|
||||
#define SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
|
||||
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class LogTagSet;
|
||||
|
||||
// Class used to temporary encode a 'what'-expression during log configuration.
|
||||
// Consists of a combination of tags and levels, e.g. "tag1+tag2=level1,tag3*=level2".
|
||||
class LogTagLevelExpression : public StackObj {
|
||||
private:
|
||||
static const size_t MaxCombinations = 32;
|
||||
static const char* DefaultExpressionString;
|
||||
|
||||
size_t _ntags, _ncombinations;
|
||||
LogTagType _tags[MaxCombinations][LogTag::MaxTags];
|
||||
LogLevelType _level[MaxCombinations];
|
||||
bool _allow_other_tags[MaxCombinations];
|
||||
char* _string;
|
||||
|
||||
void new_combination() {
|
||||
_ncombinations++;
|
||||
_ntags = 0;
|
||||
}
|
||||
|
||||
void add_tag(LogTagType tag) {
|
||||
assert(_ntags < LogTag::MaxTags, "Can't have more tags than MaxTags!");
|
||||
_tags[_ncombinations][_ntags++] = tag;
|
||||
}
|
||||
|
||||
void set_level(LogLevelType level) {
|
||||
_level[_ncombinations] = level;
|
||||
}
|
||||
|
||||
void set_allow_other_tags() {
|
||||
_allow_other_tags[_ncombinations] = true;
|
||||
}
|
||||
|
||||
void clear();
|
||||
|
||||
public:
|
||||
LogTagLevelExpression() : _ntags(0), _ncombinations(0), _string(NULL) {
|
||||
}
|
||||
|
||||
const char* to_string() const {
|
||||
return _string;
|
||||
}
|
||||
|
||||
~LogTagLevelExpression();
|
||||
bool parse(const char* str, outputStream* errstream = NULL);
|
||||
LogLevelType level_for(const LogTagSet& ts) const;
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGTAGLEVELEXPRESSION_HPP
|
92
hotspot/src/share/vm/logging/logTagSet.cpp
Normal file
92
hotspot/src/share/vm/logging/logTagSet.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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 "precompiled.hpp"
|
||||
#include "logging/logDecorations.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logOutput.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "logging/logTagSet.hpp"
|
||||
|
||||
LogTagSet* LogTagSet::_list = NULL;
|
||||
size_t LogTagSet::_ntagsets = 0;
|
||||
|
||||
// This constructor is called only during static initialization.
|
||||
// See the declaration in logTagSet.hpp for more information.
|
||||
LogTagSet::LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4)
|
||||
: _next(_list) {
|
||||
_tag[0] = t0;
|
||||
_tag[1] = t1;
|
||||
_tag[2] = t2;
|
||||
_tag[3] = t3;
|
||||
_tag[4] = t4;
|
||||
for (_ntags = 0; _ntags < LogTag::MaxTags && _tag[_ntags] != LogTag::__NO_TAG; _ntags++) {
|
||||
}
|
||||
_list = this;
|
||||
_ntagsets++;
|
||||
|
||||
// Set the default output to warning and error level for all new tagsets.
|
||||
_output_list.set_output_level(LogOutput::Stderr, LogLevel::Default);
|
||||
}
|
||||
|
||||
bool LogTagSet::is_level(LogLevelType level) {
|
||||
return _output_list.is_level(level);
|
||||
}
|
||||
|
||||
void LogTagSet::update_decorators(const LogDecorators& decorator) {
|
||||
LogDecorators new_decorators = decorator;
|
||||
for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) {
|
||||
new_decorators.combine_with((*it)->decorators());
|
||||
}
|
||||
_decorators = new_decorators;
|
||||
}
|
||||
|
||||
bool LogTagSet::has_output(const LogOutput* output) {
|
||||
for (LogOutputList::Iterator it = _output_list.iterator(); it != _output_list.end(); it++) {
|
||||
if (*it == output) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LogTagSet::log(LogLevelType level, const char* msg) {
|
||||
LogDecorations decorations(level, *this, _decorators);
|
||||
for (LogOutputList::Iterator it = _output_list.iterator(level); it != _output_list.end(); it++) {
|
||||
(*it)->write(decorations, msg);
|
||||
}
|
||||
}
|
||||
|
||||
int LogTagSet::label(char* buf, size_t len) {
|
||||
int tot_written = 0;
|
||||
for (size_t i = 0; i < _ntags; i++) {
|
||||
int written = jio_snprintf(buf + tot_written, len - tot_written, "%s%s",
|
||||
(i == 0 ? "" : ","),
|
||||
LogTag::name(_tag[i]));
|
||||
if (written < 0) {
|
||||
return -1;
|
||||
}
|
||||
tot_written += written;
|
||||
}
|
||||
return tot_written;
|
||||
}
|
114
hotspot/src/share/vm/logging/logTagSet.hpp
Normal file
114
hotspot/src/share/vm/logging/logTagSet.hpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_LOGGING_LOGTAGSET_HPP
|
||||
#define SHARE_VM_LOGGING_LOGTAGSET_HPP
|
||||
|
||||
#include "logging/logDecorators.hpp"
|
||||
#include "logging/logLevel.hpp"
|
||||
#include "logging/logOutputList.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
// The tagset represents a combination of tags that occur in a log call somewhere.
|
||||
// Tagsets are created automatically by the LogTagSetMappings and should never be
|
||||
// instantiated directly somewhere else.
|
||||
class LogTagSet VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
static LogTagSet* _list;
|
||||
static size_t _ntagsets;
|
||||
|
||||
LogTagSet* const _next;
|
||||
size_t _ntags;
|
||||
LogTagType _tag[LogTag::MaxTags];
|
||||
|
||||
LogOutputList _output_list;
|
||||
LogDecorators _decorators;
|
||||
|
||||
// Keep constructor private to prevent incorrect instantiations of this class.
|
||||
// Only LogTagSetMappings can create/contain instances of this class.
|
||||
// The constructor links all tagsets together in a global list of tagsets.
|
||||
// This list is used during configuration to be able to update all tagsets
|
||||
// and their configurations to reflect the new global log configuration.
|
||||
LogTagSet(LogTagType t0, LogTagType t1, LogTagType t2, LogTagType t3, LogTagType t4);
|
||||
|
||||
template <LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4>
|
||||
friend class LogTagSetMapping;
|
||||
|
||||
public:
|
||||
static LogTagSet* first() {
|
||||
return _list;
|
||||
}
|
||||
|
||||
LogTagSet* next() {
|
||||
return _next;
|
||||
}
|
||||
|
||||
size_t ntags() const {
|
||||
return _ntags;
|
||||
}
|
||||
|
||||
bool contains(LogTagType tag) const {
|
||||
for (size_t i = 0; _tag[i] != LogTag::__NO_TAG; i++) {
|
||||
if (tag == _tag[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_output_level(LogOutput* output, LogLevelType level) {
|
||||
_output_list.set_output_level(output, level);
|
||||
}
|
||||
|
||||
// Refresh the decorators for this tagset to contain the decorators for all
|
||||
// of its current outputs combined with the given decorators.
|
||||
void update_decorators(const LogDecorators& decorator);
|
||||
|
||||
int label(char *buf, size_t len);
|
||||
bool has_output(const LogOutput* output);
|
||||
bool is_level(LogLevelType level);
|
||||
void log(LogLevelType level, const char* msg);
|
||||
};
|
||||
|
||||
template <LogTagType T0, LogTagType T1 = LogTag::__NO_TAG, LogTagType T2 = LogTag::__NO_TAG,
|
||||
LogTagType T3 = LogTag::__NO_TAG, LogTagType T4 = LogTag::__NO_TAG>
|
||||
class LogTagSetMapping : public AllStatic {
|
||||
private:
|
||||
static LogTagSet _tagset;
|
||||
|
||||
public:
|
||||
static LogTagSet& tagset() {
|
||||
return _tagset;
|
||||
}
|
||||
};
|
||||
|
||||
// Instantiate the static field _tagset for all tagsets that are used for logging somewhere.
|
||||
// (This must be done here rather than the .cpp file because it's a template.)
|
||||
// Each combination of tags used as template arguments to the Log class somewhere (via macro or not)
|
||||
// will instantiate the LogTagSetMapping template, which in turn creates the static field for that
|
||||
// tagset. This _tagset contains the configuration for those tags.
|
||||
template <LogTagType T0, LogTagType T1, LogTagType T2, LogTagType T3, LogTagType T4>
|
||||
LogTagSet LogTagSetMapping<T0, T1, T2, T3, T4>::_tagset(T0, T1, T2, T3, T4);
|
||||
|
||||
#endif // SHARE_VM_LOGGING_LOGTAGSET_HPP
|
@ -154,8 +154,9 @@ enum MemoryType {
|
||||
mtChunk = 0x0C, // chunk that holds content of arenas
|
||||
mtTest = 0x0D, // Test type for verifying NMT
|
||||
mtTracing = 0x0E, // memory used for Tracing
|
||||
mtNone = 0x0F, // undefined
|
||||
mt_number_of_types = 0x10 // number of memory types (mtDontTrack
|
||||
mtLogging = 0x0F, // memory for logging
|
||||
mtNone = 0x10, // undefined
|
||||
mt_number_of_types = 0x11 // number of memory types (mtDontTrack
|
||||
// is not included as validate type)
|
||||
};
|
||||
|
||||
|
@ -128,6 +128,7 @@
|
||||
# include "interpreter/templateInterpreter.hpp"
|
||||
# include "interpreter/templateTable.hpp"
|
||||
# include "jvmtifiles/jvmti.h"
|
||||
# include "logging/log.hpp"
|
||||
# include "memory/allocation.hpp"
|
||||
# include "memory/allocation.inline.hpp"
|
||||
# include "memory/heap.hpp"
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "gc/shared/taskqueue.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/universe.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
@ -3190,6 +3191,26 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
|
||||
if (FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true) != Flag::SUCCESS) {
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
} else if (match_option(option, "-Xlog", &tail)) {
|
||||
bool ret = false;
|
||||
if (strcmp(tail, ":help") == 0) {
|
||||
LogConfiguration::print_command_line_help(defaultStream::output_stream());
|
||||
vm_exit(0);
|
||||
} else if (strcmp(tail, ":disable") == 0) {
|
||||
LogConfiguration::disable_logging();
|
||||
ret = true;
|
||||
} else if (*tail == '\0') {
|
||||
ret = LogConfiguration::parse_command_line_arguments();
|
||||
assert(ret, "-Xlog without arguments should never fail to parse");
|
||||
} else if (*tail == ':') {
|
||||
ret = LogConfiguration::parse_command_line_arguments(tail + 1);
|
||||
}
|
||||
if (ret == false) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"Invalid -Xlog option '-Xlog%s'\n",
|
||||
tail);
|
||||
return JNI_EINVAL;
|
||||
}
|
||||
// JNI hooks
|
||||
} else if (match_option(option, "-Xcheck", &tail)) {
|
||||
if (!strcmp(tail, ":jni")) {
|
||||
|
@ -127,6 +127,7 @@ Monitor* GCTaskManager_lock = NULL;
|
||||
Mutex* Management_lock = NULL;
|
||||
Monitor* Service_lock = NULL;
|
||||
Monitor* PeriodicTask_lock = NULL;
|
||||
Mutex* LogConfiguration_lock = NULL;
|
||||
|
||||
#ifdef INCLUDE_TRACE
|
||||
Mutex* JfrStacktrace_lock = NULL;
|
||||
@ -282,6 +283,7 @@ void mutex_init() {
|
||||
if (WhiteBoxAPI) {
|
||||
def(Compilation_lock , Monitor, leaf, false, Monitor::_safepoint_check_never);
|
||||
}
|
||||
def(LogConfiguration_lock , Mutex, nonleaf, false, Monitor::_safepoint_check_always);
|
||||
|
||||
#ifdef INCLUDE_TRACE
|
||||
def(JfrMsg_lock , Monitor, leaf, true, Monitor::_safepoint_check_always);
|
||||
|
@ -126,6 +126,7 @@ extern Mutex* MMUTracker_lock; // protects the MMU
|
||||
extern Mutex* Management_lock; // a lock used to serialize JVM management
|
||||
extern Monitor* Service_lock; // a lock used for service thread operation
|
||||
extern Monitor* PeriodicTask_lock; // protects the periodic task structure
|
||||
extern Mutex* LogConfiguration_lock; // protects configuration of logging
|
||||
|
||||
#ifdef INCLUDE_TRACE
|
||||
extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "interpreter/oopMapCache.hpp"
|
||||
#include "jvmtifiles/jvmtiEnv.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/universe.inline.hpp"
|
||||
@ -3306,6 +3307,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
// Initialize the os module before using TLS
|
||||
os::init();
|
||||
|
||||
// Record VM creation timing statistics
|
||||
TraceVmCreationTime create_vm_timer;
|
||||
create_vm_timer.start();
|
||||
|
||||
// Initialize system properties.
|
||||
Arguments::init_system_properties();
|
||||
|
||||
@ -3315,6 +3320,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
// Update/Initialize System properties after JDK version number is known
|
||||
Arguments::init_version_specific_system_properties();
|
||||
|
||||
// Make sure to initialize log configuration *before* parsing arguments
|
||||
LogConfiguration::initialize(create_vm_timer.begin_time());
|
||||
|
||||
// Parse arguments
|
||||
jint parse_result = Arguments::parse(args);
|
||||
if (parse_result != JNI_OK) return parse_result;
|
||||
@ -3341,10 +3349,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
|
||||
HOTSPOT_VM_INIT_BEGIN();
|
||||
|
||||
// Record VM creation timing statistics
|
||||
TraceVmCreationTime create_vm_timer;
|
||||
create_vm_timer.start();
|
||||
|
||||
// Timing (must come after argument parsing)
|
||||
TraceTime timer("Create VM", TraceStartupTime);
|
||||
|
||||
@ -3492,6 +3496,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
// debug stuff, that does not work until all basic classes have been initialized.
|
||||
set_init_completed();
|
||||
|
||||
LogConfiguration::post_initialize();
|
||||
Metaspace::post_initialize();
|
||||
|
||||
HOTSPOT_VM_INIT_END();
|
||||
@ -3966,6 +3971,8 @@ bool Threads::destroy_vm() {
|
||||
// exit_globals() will delete tty
|
||||
exit_globals();
|
||||
|
||||
LogConfiguration::finalize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -118,6 +118,10 @@ public:
|
||||
void start()
|
||||
{ _timer.update_to(0); _begin_time = os::javaTimeMillis(); }
|
||||
|
||||
jlong begin_time() const {
|
||||
return _begin_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only call this if initialization completes successfully; it will
|
||||
* crash if PerfMemory_exit() has already been called (usually by
|
||||
|
@ -40,6 +40,7 @@ const char* NMTUtil::_memory_type_names[] = {
|
||||
"Arena Chunk",
|
||||
"Test",
|
||||
"Tracing",
|
||||
"Logging",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
|
@ -1440,3 +1440,14 @@ bool networkStream::connect(const char *ip, short port) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void logStream::write(const char* s, size_t len) {
|
||||
if (len > 0 && s[len - 1] == '\n') {
|
||||
_current_line.write(s, len - 1);
|
||||
_log_func(_current_line.as_string());
|
||||
_current_line.reset();
|
||||
} else {
|
||||
_current_line.write(s, len);
|
||||
update_position(s, len);
|
||||
}
|
||||
}
|
||||
|
@ -235,6 +235,18 @@ class fdStream : public outputStream {
|
||||
void flush() {};
|
||||
};
|
||||
|
||||
class logStream : public outputStream {
|
||||
private:
|
||||
stringStream _current_line;
|
||||
void (*_log_func)(const char* fmt, ...);
|
||||
public:
|
||||
void write(const char* s, size_t len);
|
||||
logStream(void (*log_func)(const char* fmt, ...)) : _log_func(log_func) {}
|
||||
~logStream() {
|
||||
guarantee(_current_line.size() == 0, "Buffer not flushed. Missing call to print_cr()?");
|
||||
}
|
||||
};
|
||||
|
||||
class gcLogFileStream : public fileStream {
|
||||
protected:
|
||||
const char* _file_name;
|
||||
|
43
hotspot/test/serviceability/logging/TestBasicLogOutput.java
Normal file
43
hotspot/test/serviceability/logging/TestBasicLogOutput.java
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestBasicLogOutput
|
||||
* @summary Ensure logging can be enabled and successfully prints to stdout.
|
||||
* @library /testlibrary
|
||||
*/
|
||||
|
||||
import jdk.test.lib.ProcessTools;
|
||||
import jdk.test.lib.OutputAnalyzer;
|
||||
|
||||
public class TestBasicLogOutput {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:all=trace", "-version");
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("[logging]"); // expected tag(s)
|
||||
output.shouldContain("Log configuration fully initialized."); // expected message
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user