# HG changeset patch # User stefank # Date 1459766704 -7200 # Node ID 70413a0266d44eec0233e1de170deabc74d86fb0 # Parent 34e1821bde93df32416fa7e2295432e6f6961947 8152635: Create a UL class to represent a Log + Level combination Reviewed-by: brutisso, mlarsson, rehn diff -r 34e1821bde93 -r 70413a0266d4 hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp --- 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 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::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)); diff -r 34e1821bde93 -r 70413a0266d4 hotspot/src/share/vm/logging/log.cpp --- 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 diff -r 34e1821bde93 -r 70413a0266d4 hotspot/src/share/vm/logging/log.hpp --- 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 + template class LogImpl VALUE_OBJ_CLASS_SPEC { @@ -184,4 +202,30 @@ #undef LOG_LEVEL }; +// Combines logging tags and a logging level. +template +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::is_level(level); + } + + static void print(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2) { + va_list args; + va_start(args, fmt); + LogImpl::vwrite(level, fmt, args); + va_end(args); + } + + static outputStream* stream() { + return new logStream(&LogImpl::template write); + } +}; + #endif // SHARE_VM_LOGGING_LOG_HPP diff -r 34e1821bde93 -r 70413a0266d4 hotspot/src/share/vm/utilities/internalVMTests.cpp --- 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);