8152635: Create a UL class to represent a Log + Level combination
Reviewed-by: brutisso, mlarsson, rehn
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Mon Apr 04 11:32:04 2016 +0200
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Mon Apr 04 12:45:04 2016 +0200
@@ -2373,14 +2373,14 @@
void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const {
assert_lock_strong(&_freelistLock);
- Log(gc, freelist, census) log;
- if (!log.is_debug()) {
+ LogTarget(Debug, gc, freelist, census) log;
+ if (!log.is_enabled()) {
return;
}
AdaptiveFreeList<FreeChunk> total;
- log.debug("end sweep# " SIZE_FORMAT, sweep_count);
+ log.print("end sweep# " SIZE_FORMAT, sweep_count);
ResourceMark rm;
- outputStream* out = log.debug_stream();
+ outputStream* out = log.stream();
AdaptiveFreeList<FreeChunk>::print_labels_on(out, "size");
size_t total_free = 0;
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
@@ -2402,8 +2402,8 @@
total.set_split_deaths(total.split_deaths() + fl->split_deaths());
}
total.print_on(out, "TOTAL");
- log.debug("Total free in indexed lists " SIZE_FORMAT " words", total_free);
- log.debug("growth: %8.5f deficit: %8.5f",
+ log.print("Total free in indexed lists " SIZE_FORMAT " words", total_free);
+ log.print("growth: %8.5f deficit: %8.5f",
(double)(total.split_births()+total.coal_births()-total.split_deaths()-total.coal_deaths())/
(total.prev_sweep() != 0 ? (double)total.prev_sweep() : 1.0),
(double)(total.desired() - total.count())/(total.desired() != 0 ? (double)total.desired() : 1.0));
--- a/hotspot/src/share/vm/logging/log.cpp Mon Apr 04 11:32:04 2016 +0200
+++ b/hotspot/src/share/vm/logging/log.cpp Mon Apr 04 12:45:04 2016 +0200
@@ -93,6 +93,7 @@
Log(logging) _log;
public:
TestLogSavedConfig(const char* apply_output = NULL, const char* apply_setting = NULL) : _new_output(0) {
+ ResourceMark rm;
_saved_config = os::strdup_check_oom(LogOutput::Stdout->config_string());
bool success = LogConfiguration::parse_log_arguments("stdout", "all=off", NULL, NULL, _log.error_stream());
assert(success, "test unable to turn all off");
@@ -105,6 +106,7 @@
}
~TestLogSavedConfig() {
+ ResourceMark rm;
if (_new_output) {
bool success = LogConfiguration::parse_log_arguments(_new_output, "all=off", NULL, NULL, _log.error_stream());
assert(success, "test unable to turn all off");
@@ -154,7 +156,7 @@
ResourceMark rm;
Log(logging) log;
- TestLogSavedConfig log_cfg("stdout", "logging+test=trace");
+ TestLogSavedConfig log_cfg("stdout", "logging*=trace");
LogConfiguration::register_update_listener(&Test_logconfiguration_subscribe_helper);
@@ -267,4 +269,68 @@
}
}
+#define Test_logtarget_string_literal "First line"
+
+
+static void Test_logtarget_on() {
+ TestLogFile log_file("log_target");
+ TestLogSavedConfig tlsc(log_file.name(), "gc=debug");
+
+ LogTarget(Debug, gc) log;
+
+ assert(log.is_enabled(), "assert");
+
+ // Log the line and expect it to be available in the output file.
+ log.print(Test_logtarget_string_literal);
+
+ FILE* fp = fopen(log_file.name(), "r");
+ assert(fp != NULL, "File read error");
+
+ char output[256 /* Large enough buffer */];
+ char* res = fgets(output, sizeof(output), fp);
+ assert(res != NULL, "assert");
+
+ assert(strstr(output, Test_logtarget_string_literal) != NULL, "log line missing");
+
+ fclose(fp);
+}
+
+static void Test_logtarget_off() {
+ TestLogFile log_file("log_target");
+ TestLogSavedConfig tlsc(log_file.name(), "gc=info");
+
+ LogTarget(Debug, gc) log;
+
+ if (log.is_enabled()) {
+ // The log config could have been redirected gc=debug to a file. If gc=debug
+ // is enabled, we can only test that the LogTarget returns the same value
+ // as the log_is_enabled function. The rest of the test will be ignored.
+ assert(log.is_enabled() == log_is_enabled(Debug, gc), "assert");
+ log_warning(logging)("This test doesn't support runs with -Xlog");
+ return;
+ }
+
+ // Try to log, but expect this to be filtered out.
+ log.print(Test_logtarget_string_literal);
+
+ // Log a dummy line so that fgets doesn't return NULL because the file is empty.
+ log_info(gc)("Dummy line");
+
+ FILE* fp = fopen(log_file.name(), "r");
+ assert(fp != NULL, "File read error");
+
+ char output[256 /* Large enough buffer */];
+ char* res = fgets(output, sizeof(output), fp);
+ assert(res != NULL, "assert");
+
+ assert(strstr(output, Test_logtarget_string_literal) == NULL, "log line not missing");
+
+ fclose(fp);
+}
+
+void Test_logtarget() {
+ Test_logtarget_on();
+ Test_logtarget_off();
+}
+
#endif // PRODUCT
--- a/hotspot/src/share/vm/logging/log.hpp Mon Apr 04 11:32:04 2016 +0200
+++ b/hotspot/src/share/vm/logging/log.hpp Mon Apr 04 12:45:04 2016 +0200
@@ -106,6 +106,24 @@
va_list args);
};
+//
+// Log class that embeds both log tags and a log level.
+//
+// The class provides a way to write the tags and log level once,
+// so that redundant specification of tags or levels can be avoided.
+//
+// Example usage:
+// LogTarget(Debug, gc) out;
+// if (out.is_enabled()) {
+// ...
+// out.print("Worker: %u", i);
+// out.print(" data: %d", x);
+// ...
+// print_stats(out.stream());
+// }
+//
+#define LogTarget(level, ...) LogTargetImpl<LogLevel::level, 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 LogImpl VALUE_OBJ_CLASS_SPEC {
@@ -184,4 +202,30 @@
#undef LOG_LEVEL
};
+// Combines logging tags and a logging level.
+template <LogLevelType level, 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 LogTargetImpl {
+public:
+ // Empty constructor to avoid warnings on MSVC about unused variables
+ // when the log instance is only used for static functions.
+ LogTargetImpl() {
+ }
+
+ static bool is_enabled() {
+ return LogImpl<T0, T1, T2, T3, T4, GuardTag>::is_level(level);
+ }
+
+ static void print(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2) {
+ va_list args;
+ va_start(args, fmt);
+ LogImpl<T0, T1, T2, T3, T4, GuardTag>::vwrite(level, fmt, args);
+ va_end(args);
+ }
+
+ static outputStream* stream() {
+ return new logStream(&LogImpl<T0, T1, T2, T3, T4, GuardTag>::template write<level>);
+ }
+};
+
#endif // SHARE_VM_LOGGING_LOG_HPP
--- a/hotspot/src/share/vm/utilities/internalVMTests.cpp Mon Apr 04 11:32:04 2016 +0200
+++ b/hotspot/src/share/vm/utilities/internalVMTests.cpp Mon Apr 04 12:45:04 2016 +0200
@@ -67,6 +67,7 @@
run_unit_test(Test_linked_list);
run_unit_test(TestChunkedList_test);
run_unit_test(JSON_test);
+ run_unit_test(Test_logtarget);
run_unit_test(Test_configure_stdout);
run_unit_test(Test_logconfiguration_subscribe);
run_unit_test(Test_log_prefix);