8152635: Create a UL class to represent a Log + Level combination
Reviewed-by: brutisso, mlarsson, rehn
This commit is contained in:
parent
64efc0eb0f
commit
65a3b7e6b3
hotspot/src/share/vm
@ -2373,14 +2373,14 @@ void CompactibleFreeListSpace::check_free_list_consistency() const {
|
||||
|
||||
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 @@ void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const {
|
||||
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));
|
||||
|
@ -93,6 +93,7 @@ class TestLogSavedConfig {
|
||||
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 @@ class TestLogSavedConfig {
|
||||
}
|
||||
|
||||
~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 @@ void Test_logconfiguration_subscribe() {
|
||||
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 @@ void Test_logtagset_duplicates() {
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
@ -106,6 +106,24 @@ class LogWriteHelper : AllStatic {
|
||||
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 @@ class LogImpl VALUE_OBJ_CLASS_SPEC {
|
||||
#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
|
||||
|
@ -67,6 +67,7 @@ void InternalVMTests::run() {
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user