LogStream.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. #if !defined(KERNEL)
  36. # include <stdio.h>
  37. #endif
  38. namespace AK {
  39. const LogStream& operator<<(const LogStream& stream, const String& value)
  40. {
  41. stream.write(value.characters(), value.length());
  42. return stream;
  43. }
  44. const LogStream& operator<<(const LogStream& stream, const FlyString& value)
  45. {
  46. return stream << value.view();
  47. }
  48. const LogStream& operator<<(const LogStream& stream, const StringView& value)
  49. {
  50. stream.write(value.characters_without_null_termination(), value.length());
  51. return stream;
  52. }
  53. const LogStream& operator<<(const LogStream& stream, int value)
  54. {
  55. char buffer[32];
  56. snprintf(buffer, sizeof(buffer), "%d", value);
  57. return stream << buffer;
  58. }
  59. const LogStream& operator<<(const LogStream& stream, long value)
  60. {
  61. char buffer[32];
  62. snprintf(buffer, sizeof(buffer), "%ld", value);
  63. return stream << buffer;
  64. }
  65. const LogStream& operator<<(const LogStream& stream, long long value)
  66. {
  67. char buffer[32];
  68. snprintf(buffer, sizeof(buffer), "%lld", value);
  69. return stream << buffer;
  70. }
  71. const LogStream& operator<<(const LogStream& stream, unsigned value)
  72. {
  73. char buffer[32];
  74. snprintf(buffer, sizeof(buffer), "%u", value);
  75. return stream << buffer;
  76. }
  77. const LogStream& operator<<(const LogStream& stream, unsigned long long value)
  78. {
  79. char buffer[32];
  80. snprintf(buffer, sizeof(buffer), "%llu", value);
  81. return stream << buffer;
  82. }
  83. const LogStream& operator<<(const LogStream& stream, unsigned long value)
  84. {
  85. char buffer[32];
  86. snprintf(buffer, sizeof(buffer), "%lu", value);
  87. return stream << buffer;
  88. }
  89. const LogStream& operator<<(const LogStream& stream, const void* value)
  90. {
  91. char buffer[32];
  92. snprintf(buffer, sizeof(buffer), "%p", value);
  93. return stream << buffer;
  94. }
  95. #if defined(__serenity__) && !defined(KERNEL)
  96. static TriState got_process_name = TriState::Unknown;
  97. static char process_name_buffer[256];
  98. #endif
  99. DebugLogStream dbg()
  100. {
  101. DebugLogStream stream;
  102. // FIXME: This logic is redundant with the stuff in Format.cpp.
  103. #if defined(__serenity__) && !defined(KERNEL)
  104. if (got_process_name == TriState::Unknown) {
  105. if (get_process_name(process_name_buffer, sizeof(process_name_buffer)) == 0)
  106. got_process_name = TriState::True;
  107. else
  108. got_process_name = TriState::False;
  109. }
  110. if (got_process_name == TriState::True)
  111. stream << "\033[33;1m" << process_name_buffer << '(' << getpid() << ")\033[0m: ";
  112. #endif
  113. #if defined(__serenity__) && defined(KERNEL)
  114. if (Kernel::Processor::is_initialized() && Kernel::Thread::current())
  115. stream << "\033[34;1m[" << *Kernel::Thread::current() << "]\033[0m: ";
  116. else
  117. stream << "\033[36;1m[Kernel]\033[0m: ";
  118. #endif
  119. return stream;
  120. }
  121. #ifdef KERNEL
  122. KernelLogStream klog()
  123. {
  124. KernelLogStream stream;
  125. if (Kernel::Processor::is_initialized() && Kernel::Thread::current())
  126. stream << "\033[34;1m[" << *Kernel::Thread::current() << "]\033[0m: ";
  127. else
  128. stream << "\033[36;1m[Kernel]\033[0m: ";
  129. return stream;
  130. }
  131. #else
  132. DebugLogStream klog()
  133. {
  134. return dbg();
  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. StdLogStream::~StdLogStream()
  166. {
  167. char newline = '\n';
  168. write(&newline, 1);
  169. }
  170. void StdLogStream::write(const char* characters, int length) const
  171. {
  172. if (::write(m_fd, characters, length) < 0) {
  173. perror("StdLogStream::write");
  174. ASSERT_NOT_REACHED();
  175. }
  176. }
  177. const LogStream& operator<<(const LogStream& stream, double value)
  178. {
  179. return stream << String::format("%.4f", value);
  180. }
  181. const LogStream& operator<<(const LogStream& stream, float value)
  182. {
  183. return stream << String::format("%.4f", value);
  184. }
  185. #endif
  186. void dump_bytes(ReadonlyBytes bytes)
  187. {
  188. StringBuilder builder;
  189. u8 buffered_byte = 0;
  190. size_t nrepeat = 0;
  191. const char* prefix = "";
  192. auto flush = [&]() {
  193. if (nrepeat > 0) {
  194. if (nrepeat == 1)
  195. builder.appendf("%s0x%02x", prefix, static_cast<int>(buffered_byte));
  196. else
  197. builder.appendf("%s%zu * 0x%02x", prefix, nrepeat, static_cast<int>(buffered_byte));
  198. nrepeat = 0;
  199. prefix = ", ";
  200. }
  201. };
  202. builder.append("{ ");
  203. for (auto byte : bytes) {
  204. if (nrepeat > 0) {
  205. if (byte != buffered_byte)
  206. flush();
  207. buffered_byte = byte;
  208. nrepeat++;
  209. } else {
  210. buffered_byte = byte;
  211. nrepeat = 1;
  212. }
  213. }
  214. flush();
  215. builder.append(" }");
  216. dbg() << builder.to_string();
  217. }
  218. }