1 /*
   2  * Copyright (c) 2016, 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 #ifndef SHARE_VM_LOGGING_LOGMESSAGE_HPP
  25 #define SHARE_VM_LOGGING_LOGMESSAGE_HPP
  26 
  27 #include "precompiled.hpp"
  28 #include "logging/logDecorations.hpp"
  29 #include "logging/logLevel.hpp"
  30 #include "memory/allocation.hpp"
  31 
  32 // The LogMessage class represents a multi-part/multi-line message
  33 // that is guaranteed to be sent and written to the log outputs
  34 // in a way that prevents interleaving by other log messages.
  35 //
  36 // The interface of LogMessage is very similar to the Log class,
  37 // with printf functions for each level (trace(), debug(), etc).
  38 // The difference is that these functions will append/write to the
  39 // LogMessage, which only buffers the message-parts until the whole
  40 // message is sent to a log (using Log::write). If TLS has been
  41 // initialized, messages will be resource allocated, otherwise
  42 // they will be C heap allocated.
  43 //
  44 // Example usage:
  45 //
  46 // LogHandle(logging) log;
  47 // if (log.is_debug()) {
  48 //   ResourceMark rm;
  49 //   LogMessage msg;
  50 //   msg.debug("debug message");
  51 //   msg.trace("additional trace information");
  52 //   log.write(msg);
  53 // }
  54 //
  55 // Log outputs on trace level will see both of the messages above,
  56 // and the trace line will immediately follow the debug line.
  57 // They will have identical decorations (apart from level).
  58 // Log outputs on debug level will see the debug message,
  59 // but not the trace message.
  60 //
  61 class LogMessage : public StackObj {
  62  private:
  63   struct LogLine VALUE_OBJ_CLASS_SPEC {
  64     LogLevelType level;
  65     size_t message_offset;
  66   };
  67   static const size_t InitialLineCapacity = 10;
  68   static const size_t InitialMessageBufferCapacity = 1024;
  69   bool _c_heap_allocated;
  70   mutable bool _used;
  71 
  72   size_t _message_buffer_size;
  73   size_t _message_buffer_capacity;
  74   char* _message_buffer;
  75 
  76   size_t _line_count;
  77   size_t _line_capacity;
  78   LogLine* _lines;
  79 
  80   LogLevelType _least_detailed_level;
  81 
  82   size_t (*_prefix_fn)(char*, size_t);
  83 
  84   // Forbid copy assignment and copy constructor.
  85   void operator=(const LogMessage& ref) {}
  86   LogMessage(const LogMessage& ref) {}
  87 
  88  public:
  89 
  90   class Iterator {
  91    private:
  92     const LogMessage& _message;
  93     size_t _current_line_index;
  94     LogLevelType _level;
  95     LogDecorations &_decorations;
  96 
  97     void skip_messages_with_finer_level() {
  98       for (; _current_line_index < _message._line_count; _current_line_index++) {
  99         if (_message._lines[_current_line_index].level >= _level) {
 100           break;
 101         }
 102       }
 103     }
 104 
 105    public:
 106     Iterator(const LogMessage& message, LogLevelType level, LogDecorations& decorations)
 107         : _message(message), _level(level), _decorations(decorations), _current_line_index(0) {
 108       skip_messages_with_finer_level();
 109     }
 110 
 111     void operator++(int) {
 112       _current_line_index++;
 113       skip_messages_with_finer_level();
 114     }
 115 
 116     bool is_at_end() {
 117       return _current_line_index == _message._line_count;
 118     }
 119 
 120     const char* message() const {
 121       return _message._message_buffer + _message._lines[_current_line_index].message_offset;
 122     }
 123 
 124     const LogDecorations& decorations() {
 125       _decorations.set_level(_message._lines[_current_line_index].level);
 126       return _decorations;
 127     }
 128   };
 129 
 130   LogMessage();
 131   ~LogMessage();
 132 
 133   LogLevelType least_detailed_level() const {
 134     return _least_detailed_level;
 135   }
 136 
 137   Iterator iterator(LogLevelType level, LogDecorations& decorations) const {
 138     _used = true;
 139     return Iterator(*this, level, decorations);
 140   }
 141 
 142   // LogMessages are not automatically prefixed based on tags like regular
 143   // simple messages (see LogPrefix.hpp for more information about prefixes).
 144   // It is, however, possible to specify a prefix per LogMessage,
 145   // using set_prefix(). Lines added to the LogMessage after a prefix
 146   // function has been set will be prefixed automatically.
 147   // Setting this to NULL will disable prefixing.
 148   void set_prefix(size_t (*prefix_fn)(char*, size_t)) {
 149     _prefix_fn = prefix_fn;
 150   }
 151 
 152   ATTRIBUTE_PRINTF(3, 4)
 153   void write(LogLevelType level, const char* fmt, ...);
 154 
 155   ATTRIBUTE_PRINTF(3, 0)
 156   void vwrite(LogLevelType level, const char* fmt, va_list args);
 157 
 158 #define LOG_LEVEL(level, name) \
 159   LogMessage& v##name(const char* fmt, va_list args) ATTRIBUTE_PRINTF(2, 0); \
 160   LogMessage& name(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3);
 161   LOG_LEVEL_LIST
 162 #undef LOG_LEVEL
 163 };
 164 
 165 #endif // SHARE_VM_LOGGING_LOGMESSAGE_HPP