1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#pragma once
4
5#include "mos/syslog/debug.hpp"
6#include "mos/syslog/formatter.hpp"
7
8#include <array>
9#include <mos/refcount.hpp>
10#include <mos/string_view.hpp>
11#include <mos/type_utils.hpp>
12#include <type_traits>
13
14enum class LogLevel
15{
16 FATAL = 6,
17 EMERG = 5,
18 WARN = 4,
19 EMPH = 3,
20 INFO = 2,
21 INFO2 = 1,
22 UNSET = 0,
23};
24
25extern struct Console *printk_console;
26extern "C" int snprintf(char *__restrict str, size_t size, const char *__restrict format, ...);
27extern "C" void lprintk(LogLevel loglevel, const char *format, ...);
28
29namespace mos
30{
31 template<typename M, typename... Args>
32 struct Preformatted
33 {
34 const std::tuple<Args...> targs;
35 explicit Preformatted(M, Args... args) : targs(args...) {};
36 };
37
38 using SyslogBuffer = std::array<char, MOS_PRINTK_BUFFER_SIZE>;
39
40 struct SyslogStreamWriter : private mos::RefCounted
41 {
42 static SyslogStreamWriter NewStream(DebugFeature feature, LogLevel level, RCCore *rcCore, SyslogBuffer &buf)
43 {
44 return SyslogStreamWriter(feature, level, rcCore, buf);
45 }
46
47 ~SyslogStreamWriter();
48
49 template<typename T>
50 requires std::is_integral_v<T> inline SyslogStreamWriter &operator<<(T value)
51 {
52 if (!should_print)
53 return *this;
54
55 pos += snprintf(str: &fmtbuffer[pos], MOS_PRINTK_BUFFER_SIZE, format: "%lld", (long long) value);
56 return *this;
57 }
58
59 template<typename T>
60 requires std::is_void_v<T> inline SyslogStreamWriter &operator<<(T *ptr)
61 {
62 if (!should_print)
63 return *this;
64
65 pos += snprintf(&fmtbuffer[pos], MOS_PRINTK_BUFFER_SIZE, "%p", ptr);
66 return *this;
67 }
68
69 template<typename E>
70 requires(std::is_enum_v<E>) inline SyslogStreamWriter &operator<<(E value)
71 {
72 if (!should_print)
73 return *this;
74
75 pos += snprintf(str: &fmtbuffer[pos], MOS_PRINTK_BUFFER_SIZE, format: "%d", (int) value);
76 return *this;
77 }
78
79 inline SyslogStreamWriter &operator<<(char c)
80 {
81 if (!should_print)
82 return *this;
83
84 pos += snprintf(str: &fmtbuffer[pos], MOS_PRINTK_BUFFER_SIZE, format: "%c", c);
85 return *this;
86 }
87
88 inline SyslogStreamWriter &operator<<(const char *str)
89 {
90 if (!should_print)
91 return *this;
92
93 pos += snprintf(str: &fmtbuffer[pos], MOS_PRINTK_BUFFER_SIZE, format: "%s", str);
94 return *this;
95 }
96
97 inline SyslogStreamWriter &operator<<(mos::string_view sv)
98 {
99 if (!should_print)
100 return *this;
101
102 pos += snprintf(str: &fmtbuffer[pos], MOS_PRINTK_BUFFER_SIZE, format: "%.*s", (int) sv.size(), sv.data());
103 return *this;
104 }
105
106 template<typename M, typename... Args>
107 inline SyslogStreamWriter operator<<(const Preformatted<M, Args...> &fmt)
108 {
109 mos::FormatImpl::print_m<M>(*this, fmt.targs);
110 return *this;
111 }
112
113 private:
114 explicit SyslogStreamWriter(DebugFeature feature, LogLevel level, RCCore *rcCore, SyslogBuffer &fmtbuffer);
115
116 private:
117 SyslogBuffer &fmtbuffer;
118 size_t pos = 0;
119
120 private:
121 const u64 timestamp;
122 const DebugFeature feature;
123 const LogLevel level;
124 const bool should_print;
125 };
126
127 template<DebugFeature feature, LogLevel level>
128 struct LoggingDescriptor
129 {
130 static constexpr auto feature_value = feature;
131 static constexpr auto level_value = level;
132
133 template<typename T>
134 SyslogStreamWriter operator<<(const T &value) const
135 {
136 // copy-elision
137 return SyslogStreamWriter::NewStream(feature, level, rcCore: &RefCounter, buf&: fmtBuffer) << value;
138 }
139
140 private:
141 mutable SyslogBuffer fmtBuffer{};
142 mutable RCCore RefCounter{};
143 };
144} // namespace mos
145
146#define DefineLogStream(name, level) \
147 constexpr auto inline m##name = mos::LoggingDescriptor<_none, LogLevel::level>(); \
148 template<DebugFeature feat> \
149 constexpr auto inline d##name = mos::LoggingDescriptor<feat, LogLevel::level>()
150
151DefineLogStream(Info2, INFO2);
152DefineLogStream(Info, INFO);
153DefineLogStream(Emph, EMPH);
154DefineLogStream(Warn, WARN);
155DefineLogStream(Emerg, EMERG);
156DefineLogStream(Fatal, FATAL);
157DefineLogStream(Cont, UNSET);
158#undef DefineLogStream
159
160#define f(_fmt) formatted_type(_fmt "")
161#define fmt(_fmt, ...) mos::Preformatted(formatted_type(_fmt ""), ##__VA_ARGS__)
162
163long do_syslog(LogLevel level, const char *file, const char *func, int line, const debug_info_entry *feat, const char *fmt, ...);
164