8153945: Track if log configuration has changed during runtime
authormlarsson
Wed, 28 Feb 2018 10:37:02 +0100
changeset 49181 fde9b3c56de4
parent 49180 9637557def32
child 49182 bd1bfa4e563f
8153945: Track if log configuration has changed during runtime Reviewed-by: lfoltan, hseigel
src/hotspot/share/logging/logConfiguration.cpp
src/hotspot/share/logging/logOutput.hpp
test/hotspot/gtest/logging/test_logConfiguration.cpp
--- a/src/hotspot/share/logging/logConfiguration.cpp	Wed Feb 28 09:30:06 2018 +0100
+++ b/src/hotspot/share/logging/logConfiguration.cpp	Wed Feb 28 10:37:02 2018 +0100
@@ -78,6 +78,11 @@
 #endif
 
 void LogConfiguration::post_initialize() {
+  // Reset the reconfigured status of all outputs
+  for (size_t i = 0; i < _n_outputs; i++) {
+    _outputs[i]->_reconfigured = false;
+  }
+
   LogDiagnosticCommand::registerCommand();
   Log(logging) log;
   if (log.is_info()) {
@@ -213,6 +218,8 @@
   assert(idx < _n_outputs, "Invalid index, idx = " SIZE_FORMAT " and _n_outputs = " SIZE_FORMAT, idx, _n_outputs);
   LogOutput* output = _outputs[idx];
 
+  output->_reconfigured = true;
+
   // Clear the previous config description
   output->clear_config_string();
 
@@ -447,7 +454,7 @@
   return true;
 }
 
-void LogConfiguration::describe_available(outputStream* out){
+void LogConfiguration::describe_available(outputStream* out) {
   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)));
@@ -467,11 +474,14 @@
   LogTagSet::describe_tagsets(out);
 }
 
-void LogConfiguration::describe_current_configuration(outputStream* out){
+void LogConfiguration::describe_current_configuration(outputStream* out) {
   out->print_cr("Log output configuration:");
   for (size_t i = 0; i < _n_outputs; i++) {
     out->print(" #" SIZE_FORMAT ": ", i);
     _outputs[i]->describe(out);
+    if (_outputs[i]->is_reconfigured()) {
+      out->print(" (reconfigured)");
+    }
     out->cr();
   }
 }
--- a/src/hotspot/share/logging/logOutput.hpp	Wed Feb 28 09:30:06 2018 +0100
+++ b/src/hotspot/share/logging/logOutput.hpp	Wed Feb 28 10:37:02 2018 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, 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
@@ -43,6 +43,12 @@
 
  private:
   static const size_t InitialConfigBufferSize = 256;
+
+  // Track if the output has been reconfigured dynamically during runtime.
+  // The status is set each time the configuration of the output is modified,
+  // and is reset once after logging initialization is complete.
+  bool _reconfigured;
+
   char* _config_string;
   size_t _config_string_buffer_size;
 
@@ -65,11 +71,15 @@
     return _decorators;
   }
 
+  bool is_reconfigured() const {
+    return _reconfigured;
+  }
+
   const char* config_string() const {
     return _config_string;
   }
 
-  LogOutput() : _config_string(NULL), _config_string_buffer_size(0) {
+  LogOutput() : _reconfigured(false), _config_string(NULL), _config_string_buffer_size(0) {
   }
 
   virtual ~LogOutput();
--- a/test/hotspot/gtest/logging/test_logConfiguration.cpp	Wed Feb 28 09:30:06 2018 +0100
+++ b/test/hotspot/gtest/logging/test_logConfiguration.cpp	Wed Feb 28 10:37:02 2018 +0100
@@ -225,7 +225,7 @@
 
   // Now reconfigure logging on stderr with no decorators
   set_log_config("stderr", "all=off", "none");
-  EXPECT_TRUE(is_described("#1: stderr all=off none\n")) << "Expecting no decorators";
+  EXPECT_TRUE(is_described("#1: stderr all=off none (reconfigured)\n")) << "Expecting no decorators";
 }
 
 // Test that invalid options cause configuration errors
@@ -414,6 +414,33 @@
   delete_file(buf);
 }
 
+static size_t count_occurrences(const char* haystack, const char* needle) {
+  size_t count = 0;
+  for (const char* p = strstr(haystack, needle); p != NULL; p = strstr(p + 1, needle)) {
+    count++;
+  }
+  return count;
+}
+
+TEST_OTHER_VM(LogConfiguration, output_reconfigured) {
+  ResourceMark rm;
+  stringStream ss;
+
+  EXPECT_FALSE(is_described("(reconfigured)"));
+
+  bool success = LogConfiguration::parse_log_arguments("#1", "all=warning", NULL, NULL, &ss);
+  ASSERT_TRUE(success);
+  EXPECT_EQ(0u, ss.size());
+
+  LogConfiguration::describe(&ss);
+  EXPECT_EQ(1u, count_occurrences(ss.as_string(), "(reconfigured)"));
+
+  ss.reset();
+  LogConfiguration::configure_stdout(LogLevel::Info, false, LOG_TAGS(logging));
+  LogConfiguration::describe(&ss);
+  EXPECT_EQ(2u, count_occurrences(ss.as_string(), "(reconfigured)"));
+}
+
 TEST_VM_F(LogConfigurationTest, suggest_similar_selection) {
   static const char* nonexisting_tagset = "logging+start+exit+safepoint+gc";