LogStream.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. #pragma once
  27. #include <AK/Format.h>
  28. #include <AK/Forward.h>
  29. #include <AK/Types.h>
  30. #include <AK/kmalloc.h>
  31. #include <AK/kstdio.h>
  32. #if !defined(KERNEL)
  33. # include <AK/ScopedValueRollback.h>
  34. # include <AK/StringView.h>
  35. # include <errno.h>
  36. # include <unistd.h>
  37. #endif
  38. namespace AK {
  39. class LogStream {
  40. public:
  41. LogStream()
  42. #if !defined(KERNEL)
  43. : m_errno_restorer(errno)
  44. #endif
  45. {
  46. }
  47. virtual ~LogStream() { }
  48. virtual void write(const char*, int) const = 0;
  49. private:
  50. #if !defined(KERNEL)
  51. ScopedValueRollback<int> m_errno_restorer;
  52. #endif
  53. };
  54. class BufferedLogStream : public LogStream {
  55. mutable size_t m_size { 0 };
  56. mutable size_t m_capacity { 128 };
  57. union {
  58. mutable u8* m_buffer { nullptr };
  59. mutable u8 m_local_buffer[128];
  60. } u;
  61. void grow(size_t bytes_needed) const
  62. {
  63. size_t new_capacity = (m_size + bytes_needed + 0x7F) & ~0x7F;
  64. u8* new_data = static_cast<u8*>(kmalloc(new_capacity));
  65. if (m_capacity <= sizeof(u.m_local_buffer)) {
  66. __builtin_memcpy(new_data, u.m_local_buffer, m_size);
  67. } else if (u.m_buffer) {
  68. __builtin_memcpy(new_data, u.m_buffer, m_size);
  69. kfree(u.m_buffer);
  70. }
  71. u.m_buffer = new_data;
  72. m_capacity = new_capacity;
  73. }
  74. protected:
  75. u8* data() const
  76. {
  77. if (m_capacity <= sizeof(u.m_local_buffer))
  78. return u.m_local_buffer;
  79. return u.m_buffer;
  80. }
  81. size_t size() const { return m_size; }
  82. bool empty() const { return m_size == 0; }
  83. public:
  84. BufferedLogStream() { }
  85. virtual ~BufferedLogStream() override
  86. {
  87. if (m_capacity > sizeof(u.m_local_buffer))
  88. kfree(u.m_buffer);
  89. }
  90. virtual void write(const char* str, int len) const override
  91. {
  92. size_t new_size = m_size + len;
  93. if (new_size > m_capacity)
  94. grow(len);
  95. __builtin_memcpy(data() + m_size, str, len);
  96. m_size = new_size;
  97. }
  98. };
  99. class DebugLogStream final : public BufferedLogStream {
  100. public:
  101. DebugLogStream() { }
  102. virtual ~DebugLogStream() override;
  103. // DebugLogStream only checks `enabled` and possibly generates output while the destructor runs.
  104. static void set_enabled(bool);
  105. static bool is_enabled();
  106. private:
  107. static bool s_enabled;
  108. };
  109. #if !defined(KERNEL)
  110. class StdLogStream final : public LogStream {
  111. public:
  112. StdLogStream(int fd)
  113. : m_fd(fd)
  114. {
  115. }
  116. virtual ~StdLogStream() override;
  117. virtual void write(const char* characters, int length) const override;
  118. private:
  119. int m_fd { -1 };
  120. };
  121. inline StdLogStream out() { return StdLogStream(STDOUT_FILENO); }
  122. inline StdLogStream warn() { return StdLogStream(STDERR_FILENO); }
  123. #endif
  124. #ifdef KERNEL
  125. class KernelLogStream final : public BufferedLogStream {
  126. public:
  127. KernelLogStream() { }
  128. virtual ~KernelLogStream() override;
  129. };
  130. #endif
  131. inline const LogStream& operator<<(const LogStream& stream, const char* value)
  132. {
  133. if (!value)
  134. return stream << "(null)";
  135. int length = 0;
  136. const char* p = value;
  137. while (*(p++))
  138. ++length;
  139. stream.write(value, length);
  140. return stream;
  141. }
  142. const LogStream& operator<<(const LogStream&, const FlyString&);
  143. const LogStream& operator<<(const LogStream&, const String&);
  144. const LogStream& operator<<(const LogStream&, const StringView&);
  145. const LogStream& operator<<(const LogStream&, int);
  146. const LogStream& operator<<(const LogStream&, long);
  147. const LogStream& operator<<(const LogStream&, unsigned);
  148. const LogStream& operator<<(const LogStream&, long long);
  149. const LogStream& operator<<(const LogStream&, unsigned long);
  150. const LogStream& operator<<(const LogStream&, unsigned long long);
  151. #if !defined(KERNEL)
  152. const LogStream& operator<<(const LogStream&, double);
  153. const LogStream& operator<<(const LogStream&, float);
  154. #endif
  155. template<typename T>
  156. const LogStream& operator<<(const LogStream& stream, Span<T> span)
  157. {
  158. return stream << "{ " << span.data() << ", " << span.size() << " }";
  159. }
  160. const LogStream& operator<<(const LogStream&, const void*);
  161. inline const LogStream& operator<<(const LogStream& stream, char value)
  162. {
  163. stream.write(&value, 1);
  164. return stream;
  165. }
  166. inline const LogStream& operator<<(const LogStream& stream, bool value)
  167. {
  168. return stream << (value ? "true" : "false");
  169. }
  170. DebugLogStream dbg();
  171. #ifdef KERNEL
  172. KernelLogStream klog();
  173. #else
  174. DebugLogStream klog();
  175. #endif
  176. void dump_bytes(ReadonlyBytes);
  177. }
  178. using AK::dbg;
  179. using AK::klog;
  180. using AK::LogStream;
  181. #if !defined(KERNEL)
  182. using AK::out;
  183. using AK::warn;
  184. #endif