src/hotspot/share/jfr/utilities/jfrJavaLog.cpp
changeset 50113 caf115bb98ad
child 54847 59ea39bb2809
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     1 /*
       
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "precompiled.hpp"
       
    26 #include "jfr/jni/jfrJavaSupport.hpp"
       
    27 #include "jfr/utilities/jfrJavaLog.hpp"
       
    28 #include "jfr/utilities/jfrLogTagSets.hpp"
       
    29 #include "logging/log.hpp"
       
    30 #include "logging/logConfiguration.hpp"
       
    31 #include "memory/resourceArea.hpp"
       
    32 #include "runtime/thread.inline.hpp"
       
    33 
       
    34 #define JFR_LOG_TAGS_CONCATED(T0, T1, T2, T3, T4, T5, ...)  \
       
    35   T0 ## _ ## T1 ## _ ## T2 ## _ ## T3 ## _ ## T4 ## _ ## T5
       
    36 
       
    37 enum JfrLogTagSetType {
       
    38 #define JFR_LOG_TAG(...) \
       
    39     EXPAND_VARARGS(JFR_LOG_TAGS_CONCATED(__VA_ARGS__, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG)),
       
    40 
       
    41     JFR_LOG_TAG_SET_LIST
       
    42 
       
    43 #undef JFR_LOG_TAG
       
    44     JFR_LOG_TAG_SET_COUNT
       
    45 };
       
    46 
       
    47 struct jfrLogSubscriber
       
    48 {
       
    49   jobject log_tag_enum_ref;
       
    50   LogTagSet* log_tag_set;
       
    51 };
       
    52 
       
    53 static jfrLogSubscriber log_tag_sets[JFR_LOG_TAG_SET_COUNT];
       
    54 
       
    55 static void log_cfg_update(LogLevelType llt, JfrLogTagSetType jflt, TRAPS) {
       
    56   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
       
    57   if (log_tag_sets[jflt].log_tag_enum_ref == NULL) {
       
    58     return;
       
    59   }
       
    60   jobject lt = log_tag_sets[jflt].log_tag_enum_ref;
       
    61   // set field tagSetLevel to llt value
       
    62   JavaValue result(T_VOID);
       
    63   JfrJavaArguments args(&result);
       
    64   args.set_klass(JfrJavaSupport::klass(lt));
       
    65   args.set_name("tagSetLevel", CHECK);
       
    66   args.set_signature("I", CHECK);
       
    67   args.set_receiver(JfrJavaSupport::resolve_non_null(lt));
       
    68   args.push_int(llt);
       
    69   JfrJavaSupport::set_field(&args, THREAD);
       
    70 }
       
    71 
       
    72 static LogLevelType highest_level(const LogTagSet& lts) {
       
    73   for (size_t i = 0; i < LogLevel::Count; i++) {
       
    74     if (lts.is_level((LogLevelType)i)) {
       
    75       return (LogLevelType)i;
       
    76     }
       
    77   }
       
    78   return LogLevel::Off;
       
    79 }
       
    80 
       
    81 static void log_config_change_internal(bool init, TRAPS) {
       
    82   LogLevelType llt;
       
    83   LogTagSet* lts;
       
    84 
       
    85 #define JFR_LOG_TAG(...) \
       
    86   lts = &LogTagSetMapping<LOG_TAGS(__VA_ARGS__)>::tagset(); \
       
    87   if (init) { \
       
    88     JfrLogTagSetType tagSetType = \
       
    89       EXPAND_VARARGS(JFR_LOG_TAGS_CONCATED(__VA_ARGS__, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG)); \
       
    90     assert(NULL == log_tag_sets[tagSetType].log_tag_set, "Init JFR LogTagSets twice"); \
       
    91     log_tag_sets[tagSetType].log_tag_set = lts; \
       
    92   } \
       
    93   llt = highest_level(*lts); \
       
    94   log_cfg_update(llt, \
       
    95   EXPAND_VARARGS(JFR_LOG_TAGS_CONCATED(__VA_ARGS__, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG, _NO_TAG)), THREAD);
       
    96   JFR_LOG_TAG_SET_LIST
       
    97 #undef JFR_LOG_TAG
       
    98 }
       
    99 
       
   100 static void log_config_change() {
       
   101   Thread* t = Thread::current();
       
   102   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));
       
   103   log_config_change_internal(false, t);
       
   104 }
       
   105 
       
   106 void JfrJavaLog::subscribe_log_level(jobject log_tag, jint id, TRAPS) {
       
   107   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
       
   108   static bool subscribed_updates = true;
       
   109   assert(id < JFR_LOG_TAG_SET_COUNT,
       
   110     "LogTag id, java and native not in synch, %d < %d", id, JFR_LOG_TAG_SET_COUNT);
       
   111   assert(NULL == log_tag_sets[id].log_tag_enum_ref, "Subscribing twice");
       
   112   log_tag_sets[id].log_tag_enum_ref = JfrJavaSupport::global_jni_handle(log_tag, THREAD);
       
   113   if (subscribed_updates) {
       
   114     LogConfiguration::register_update_listener(&log_config_change);
       
   115     log_config_change_internal(true, THREAD);
       
   116     subscribed_updates = false;
       
   117   } else {
       
   118     log_config_change_internal(false, THREAD);
       
   119   }
       
   120 }
       
   121 
       
   122 void JfrJavaLog::log(jint tag_set, jint level, jstring message, TRAPS) {
       
   123   DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
       
   124   if (message == NULL) {
       
   125     return;
       
   126   }
       
   127   if (level < (jint)LogLevel::First || level > (jint)LogLevel::Last) {
       
   128     JfrJavaSupport::throw_illegal_argument_exception("LogLevel passed is outside valid range", THREAD);
       
   129     return;
       
   130   }
       
   131   if (tag_set < 0 || tag_set >= (jint)JFR_LOG_TAG_SET_COUNT) {
       
   132     JfrJavaSupport::throw_illegal_argument_exception("LogTagSet id is outside valid range", THREAD);
       
   133     return;
       
   134   }
       
   135   ResourceMark rm(THREAD);
       
   136   const char* const s = JfrJavaSupport::c_str(message, CHECK);
       
   137   assert(s != NULL, "invariant");
       
   138   assert(log_tag_sets[tag_set].log_tag_set != NULL, "LogTagSet is not init");
       
   139   log_tag_sets[tag_set].log_tag_set->log((LogLevelType)level, s);
       
   140 }