--- a/hotspot/make/windows/makefiles/vm.make Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/make/windows/makefiles/vm.make Thu Sep 24 12:36:04 2015 +0200
@@ -163,6 +163,7 @@
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 @@
{$(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 @@
{$(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 $<
--- a/hotspot/src/share/vm/Xusage.txt Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/Xusage.txt Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/log.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logConfiguration.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorations.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorations.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorators.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDecorators.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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());
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logDiagnosticCommand.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileOutput.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileOutput.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileStreamOutput.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logFileStreamOutput.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logLevel.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logLevel.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutput.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutput.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutputList.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logOutputList.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logPrefix.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTag.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTag.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagLevelExpression.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagLevelExpression.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagSet.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTagSet.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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
--- a/hotspot/src/share/vm/memory/allocation.hpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/memory/allocation.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -154,8 +154,9 @@
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)
};
--- a/hotspot/src/share/vm/precompiled/precompiled.hpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/precompiled/precompiled.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -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"
--- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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 @@
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")) {
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -127,6 +127,7 @@
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 @@
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);
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -126,6 +126,7 @@
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
--- a/hotspot/src/share/vm/runtime/thread.cpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -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 @@
// 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 @@
// 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 @@
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 @@
// 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 @@
// exit_globals() will delete tty
exit_globals();
+ LogConfiguration::finalize();
+
return true;
}
--- a/hotspot/src/share/vm/services/management.hpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/services/management.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -118,6 +118,10 @@
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
--- a/hotspot/src/share/vm/services/nmtCommon.cpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/services/nmtCommon.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -40,6 +40,7 @@
"Arena Chunk",
"Test",
"Tracing",
+ "Logging",
"Unknown"
};
--- a/hotspot/src/share/vm/utilities/ostream.cpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Thu Sep 24 12:36:04 2015 +0200
@@ -1440,3 +1440,14 @@
}
#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);
+ }
+}
--- a/hotspot/src/share/vm/utilities/ostream.hpp Wed Sep 23 22:04:23 2015 +0300
+++ b/hotspot/src/share/vm/utilities/ostream.hpp Thu Sep 24 12:36:04 2015 +0200
@@ -235,6 +235,18 @@
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;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/logging/TestBasicLogOutput.java Thu Sep 24 12:36:04 2015 +0200
@@ -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);
+ }
+}
+