LogStream.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/FlyString.h>
  27. #include <AK/LogStream.h>
  28. #include <AK/String.h>
  29. #include <AK/StringBuilder.h>
  30. #include <AK/StringView.h>
  31. #ifdef KERNEL
  32. # include <Kernel/Process.h>
  33. # include <Kernel/Thread.h>
  34. #endif
  35. namespace AK {
  36. const LogStream& operator<<(const LogStream& stream, const String& value)
  37. {
  38. stream.write(value.characters(), value.length());
  39. return stream;
  40. }
  41. const LogStream& operator<<(const LogStream& stream, const FlyString& value)
  42. {
  43. return stream << value.view();
  44. }
  45. const LogStream& operator<<(const LogStream& stream, const StringView& value)
  46. {
  47. stream.write(value.characters_without_null_termination(), value.length());
  48. return stream;
  49. }
  50. const LogStream& operator<<(const LogStream& stream, int value)
  51. {
  52. char buffer[32];
  53. snprintf(buffer, sizeof(buffer), "%d", value);
  54. return stream << buffer;
  55. }
  56. const LogStream& operator<<(const LogStream& stream, long value)
  57. {
  58. char buffer[32];
  59. snprintf(buffer, sizeof(buffer), "%ld", value);
  60. return stream << buffer;
  61. }
  62. const LogStream& operator<<(const LogStream& stream, long long value)
  63. {
  64. char buffer[32];
  65. snprintf(buffer, sizeof(buffer), "%lld", value);
  66. return stream << buffer;
  67. }
  68. const LogStream& operator<<(const LogStream& stream, unsigned value)
  69. {
  70. char buffer[32];
  71. snprintf(buffer, sizeof(buffer), "%u", value);
  72. return stream << buffer;
  73. }
  74. const LogStream& operator<<(const LogStream& stream, unsigned long long value)
  75. {
  76. char buffer[32];
  77. snprintf(buffer, sizeof(buffer), "%llu", value);
  78. return stream << buffer;
  79. }
  80. const LogStream& operator<<(const LogStream& stream, unsigned long value)
  81. {
  82. char buffer[32];
  83. snprintf(buffer, sizeof(buffer), "%lu", value);
  84. return stream << buffer;
  85. }
  86. const LogStream& operator<<(const LogStream& stream, const void* value)
  87. {
  88. char buffer[32];
  89. snprintf(buffer, sizeof(buffer), "%p", value);
  90. return stream << buffer;
  91. }
  92. #if defined(__serenity__) && !defined(KERNEL)
  93. static TriState got_process_name = TriState::Unknown;
  94. static char process_name_buffer[256];
  95. #endif
  96. DebugLogStream dbg()
  97. {
  98. DebugLogStream stream;
  99. // FIXME: This logic is redundant with the stuff in Format.cpp.
  100. #if defined(__serenity__) && !defined(KERNEL)
  101. if (got_process_name == TriState::Unknown) {
  102. if (get_process_name(process_name_buffer, sizeof(process_name_buffer)) == 0)
  103. got_process_name = TriState::True;
  104. else
  105. got_process_name = TriState::False;
  106. }
  107. if (got_process_name == TriState::True)
  108. stream << "\033[33;1m" << process_name_buffer << '(' << getpid() << ")\033[0m: ";
  109. #endif
  110. #if defined(__serenity__) && defined(KERNEL)
  111. if (Kernel::Processor::is_initialized() && Kernel::Thread::current())
  112. stream << "\033[34;1m[#" << Kernel::Processor::id() << " " << *Kernel::Thread::current() << "]\033[0m: ";
  113. else
  114. stream << "\033[36;1m[Kernel]\033[0m: ";
  115. #endif
  116. return stream;
  117. }
  118. #ifdef KERNEL
  119. KernelLogStream klog()
  120. {
  121. KernelLogStream stream;
  122. if (Kernel::Processor::is_initialized() && Kernel::Thread::current())
  123. stream << "\033[34;1m[#" << Kernel::Processor::id() << " " << *Kernel::Thread::current() << "]\033[0m: ";
  124. else
  125. stream << "\033[36;1m[Kernel]\033[0m: ";
  126. return stream;
  127. }
  128. #else
  129. DebugLogStream klog()
  130. {
  131. # pragma GCC diagnostic push
  132. # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  133. return dbg();
  134. # pragma GCC diagnostic pop
  135. }
  136. #endif
  137. #ifdef KERNEL
  138. KernelLogStream::~KernelLogStream()
  139. {
  140. if (!empty()) {
  141. char newline = '\n';
  142. write(&newline, 1);
  143. kernelputstr(reinterpret_cast<char*>(data()), size());
  144. }
  145. }
  146. #endif
  147. DebugLogStream::~DebugLogStream()
  148. {
  149. if (!empty() && s_enabled) {
  150. char newline = '\n';
  151. write(&newline, 1);
  152. dbgputstr(reinterpret_cast<char*>(data()), size());
  153. }
  154. }
  155. void DebugLogStream::set_enabled(bool enabled)
  156. {
  157. s_enabled = enabled;
  158. }
  159. bool DebugLogStream::is_enabled()
  160. {
  161. return s_enabled;
  162. }
  163. bool DebugLogStream::s_enabled = true;
  164. #ifndef KERNEL
  165. const LogStream& operator<<(const LogStream& stream, double value)
  166. {
  167. return stream << String::format("%.4f", value);
  168. }
  169. const LogStream& operator<<(const LogStream& stream, float value)
  170. {
  171. return stream << String::format("%.4f", value);
  172. }
  173. #endif
  174. void dump_bytes(ReadonlyBytes bytes)
  175. {
  176. StringBuilder builder;
  177. u8 buffered_byte = 0;
  178. size_t nrepeat = 0;
  179. const char* prefix = "";
  180. auto flush = [&]() {
  181. if (nrepeat > 0) {
  182. if (nrepeat == 1)
  183. builder.appendff("{}{:#02x}", prefix, static_cast<int>(buffered_byte));
  184. else
  185. builder.appendff("{}{} * {:#02x}", prefix, nrepeat, static_cast<int>(buffered_byte));
  186. nrepeat = 0;
  187. prefix = ", ";
  188. }
  189. };
  190. builder.append("{ ");
  191. for (auto byte : bytes) {
  192. if (nrepeat > 0) {
  193. if (byte != buffered_byte)
  194. flush();
  195. buffered_byte = byte;
  196. nrepeat++;
  197. } else {
  198. buffered_byte = byte;
  199. nrepeat = 1;
  200. }
  201. }
  202. flush();
  203. builder.append(" }");
  204. dbgln("{}", builder.string_view());
  205. }
  206. }