1*9356374aSAndroid Build Coastguard Worker // Copyright 2017 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker
15*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/raw_logging.h"
16*9356374aSAndroid Build Coastguard Worker
17*9356374aSAndroid Build Coastguard Worker #include <cstdarg>
18*9356374aSAndroid Build Coastguard Worker #include <cstddef>
19*9356374aSAndroid Build Coastguard Worker #include <cstdio>
20*9356374aSAndroid Build Coastguard Worker #include <cstdlib>
21*9356374aSAndroid Build Coastguard Worker #include <cstring>
22*9356374aSAndroid Build Coastguard Worker #include <string>
23*9356374aSAndroid Build Coastguard Worker
24*9356374aSAndroid Build Coastguard Worker #ifdef __EMSCRIPTEN__
25*9356374aSAndroid Build Coastguard Worker #include <emscripten/console.h>
26*9356374aSAndroid Build Coastguard Worker #endif
27*9356374aSAndroid Build Coastguard Worker
28*9356374aSAndroid Build Coastguard Worker #include "absl/base/attributes.h"
29*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
30*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/atomic_hook.h"
31*9356374aSAndroid Build Coastguard Worker #include "absl/base/internal/errno_saver.h"
32*9356374aSAndroid Build Coastguard Worker #include "absl/base/log_severity.h"
33*9356374aSAndroid Build Coastguard Worker
34*9356374aSAndroid Build Coastguard Worker // We know how to perform low-level writes to stderr in POSIX and Windows. For
35*9356374aSAndroid Build Coastguard Worker // these platforms, we define the token ABSL_LOW_LEVEL_WRITE_SUPPORTED.
36*9356374aSAndroid Build Coastguard Worker // Much of raw_logging.cc becomes a no-op when we can't output messages,
37*9356374aSAndroid Build Coastguard Worker // although a FATAL ABSL_RAW_LOG message will still abort the process.
38*9356374aSAndroid Build Coastguard Worker
39*9356374aSAndroid Build Coastguard Worker // ABSL_HAVE_POSIX_WRITE is defined when the platform provides posix write()
40*9356374aSAndroid Build Coastguard Worker // (as from unistd.h)
41*9356374aSAndroid Build Coastguard Worker //
42*9356374aSAndroid Build Coastguard Worker // This preprocessor token is also defined in raw_io.cc. If you need to copy
43*9356374aSAndroid Build Coastguard Worker // this, consider moving both to config.h instead.
44*9356374aSAndroid Build Coastguard Worker #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
45*9356374aSAndroid Build Coastguard Worker defined(__hexagon__) || defined(__Fuchsia__) || \
46*9356374aSAndroid Build Coastguard Worker defined(__native_client__) || defined(__OpenBSD__) || \
47*9356374aSAndroid Build Coastguard Worker defined(__EMSCRIPTEN__) || defined(__ASYLO__)
48*9356374aSAndroid Build Coastguard Worker
49*9356374aSAndroid Build Coastguard Worker #include <unistd.h>
50*9356374aSAndroid Build Coastguard Worker
51*9356374aSAndroid Build Coastguard Worker #define ABSL_HAVE_POSIX_WRITE 1
52*9356374aSAndroid Build Coastguard Worker #define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
53*9356374aSAndroid Build Coastguard Worker #else
54*9356374aSAndroid Build Coastguard Worker #undef ABSL_HAVE_POSIX_WRITE
55*9356374aSAndroid Build Coastguard Worker #endif
56*9356374aSAndroid Build Coastguard Worker
57*9356374aSAndroid Build Coastguard Worker // ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall
58*9356374aSAndroid Build Coastguard Worker // syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len);
59*9356374aSAndroid Build Coastguard Worker // for low level operations that want to avoid libc.
60*9356374aSAndroid Build Coastguard Worker #if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
61*9356374aSAndroid Build Coastguard Worker #include <sys/syscall.h>
62*9356374aSAndroid Build Coastguard Worker #define ABSL_HAVE_SYSCALL_WRITE 1
63*9356374aSAndroid Build Coastguard Worker #define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
64*9356374aSAndroid Build Coastguard Worker #else
65*9356374aSAndroid Build Coastguard Worker #undef ABSL_HAVE_SYSCALL_WRITE
66*9356374aSAndroid Build Coastguard Worker #endif
67*9356374aSAndroid Build Coastguard Worker
68*9356374aSAndroid Build Coastguard Worker #ifdef _WIN32
69*9356374aSAndroid Build Coastguard Worker #include <io.h>
70*9356374aSAndroid Build Coastguard Worker
71*9356374aSAndroid Build Coastguard Worker #define ABSL_HAVE_RAW_IO 1
72*9356374aSAndroid Build Coastguard Worker #define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1
73*9356374aSAndroid Build Coastguard Worker #else
74*9356374aSAndroid Build Coastguard Worker #undef ABSL_HAVE_RAW_IO
75*9356374aSAndroid Build Coastguard Worker #endif
76*9356374aSAndroid Build Coastguard Worker
77*9356374aSAndroid Build Coastguard Worker namespace absl {
78*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
79*9356374aSAndroid Build Coastguard Worker namespace raw_log_internal {
80*9356374aSAndroid Build Coastguard Worker namespace {
81*9356374aSAndroid Build Coastguard Worker
82*9356374aSAndroid Build Coastguard Worker // TODO(gfalcon): We want raw-logging to work on as many platforms as possible.
83*9356374aSAndroid Build Coastguard Worker // Explicitly `#error` out when not `ABSL_LOW_LEVEL_WRITE_SUPPORTED`, except for
84*9356374aSAndroid Build Coastguard Worker // a selected set of platforms for which we expect not to be able to raw log.
85*9356374aSAndroid Build Coastguard Worker
86*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
87*9356374aSAndroid Build Coastguard Worker constexpr char kTruncated[] = " ... (message truncated)\n";
88*9356374aSAndroid Build Coastguard Worker
89*9356374aSAndroid Build Coastguard Worker // sprintf the format to the buffer, adjusting *buf and *size to reflect the
90*9356374aSAndroid Build Coastguard Worker // consumed bytes, and return whether the message fit without truncation. If
91*9356374aSAndroid Build Coastguard Worker // truncation occurred, if possible leave room in the buffer for the message
92*9356374aSAndroid Build Coastguard Worker // kTruncated[].
93*9356374aSAndroid Build Coastguard Worker bool VADoRawLog(char** buf, int* size, const char* format, va_list ap)
94*9356374aSAndroid Build Coastguard Worker ABSL_PRINTF_ATTRIBUTE(3, 0);
VADoRawLog(char ** buf,int * size,const char * format,va_list ap)95*9356374aSAndroid Build Coastguard Worker bool VADoRawLog(char** buf, int* size, const char* format, va_list ap) {
96*9356374aSAndroid Build Coastguard Worker if (*size < 0) return false;
97*9356374aSAndroid Build Coastguard Worker int n = vsnprintf(*buf, static_cast<size_t>(*size), format, ap);
98*9356374aSAndroid Build Coastguard Worker bool result = true;
99*9356374aSAndroid Build Coastguard Worker if (n < 0 || n > *size) {
100*9356374aSAndroid Build Coastguard Worker result = false;
101*9356374aSAndroid Build Coastguard Worker if (static_cast<size_t>(*size) > sizeof(kTruncated)) {
102*9356374aSAndroid Build Coastguard Worker n = *size - static_cast<int>(sizeof(kTruncated));
103*9356374aSAndroid Build Coastguard Worker } else {
104*9356374aSAndroid Build Coastguard Worker n = 0; // no room for truncation message
105*9356374aSAndroid Build Coastguard Worker }
106*9356374aSAndroid Build Coastguard Worker }
107*9356374aSAndroid Build Coastguard Worker *size -= n;
108*9356374aSAndroid Build Coastguard Worker *buf += n;
109*9356374aSAndroid Build Coastguard Worker return result;
110*9356374aSAndroid Build Coastguard Worker }
111*9356374aSAndroid Build Coastguard Worker #endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED
112*9356374aSAndroid Build Coastguard Worker
113*9356374aSAndroid Build Coastguard Worker constexpr int kLogBufSize = 3000;
114*9356374aSAndroid Build Coastguard Worker
115*9356374aSAndroid Build Coastguard Worker // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
116*9356374aSAndroid Build Coastguard Worker // that invoke malloc() and getenv() that might acquire some locks.
117*9356374aSAndroid Build Coastguard Worker
118*9356374aSAndroid Build Coastguard Worker // Helper for RawLog below.
119*9356374aSAndroid Build Coastguard Worker // *DoRawLog writes to *buf of *size and move them past the written portion.
120*9356374aSAndroid Build Coastguard Worker // It returns true iff there was no overflow or error.
121*9356374aSAndroid Build Coastguard Worker bool DoRawLog(char** buf, int* size, const char* format, ...)
122*9356374aSAndroid Build Coastguard Worker ABSL_PRINTF_ATTRIBUTE(3, 4);
DoRawLog(char ** buf,int * size,const char * format,...)123*9356374aSAndroid Build Coastguard Worker bool DoRawLog(char** buf, int* size, const char* format, ...) {
124*9356374aSAndroid Build Coastguard Worker if (*size < 0) return false;
125*9356374aSAndroid Build Coastguard Worker va_list ap;
126*9356374aSAndroid Build Coastguard Worker va_start(ap, format);
127*9356374aSAndroid Build Coastguard Worker int n = vsnprintf(*buf, static_cast<size_t>(*size), format, ap);
128*9356374aSAndroid Build Coastguard Worker va_end(ap);
129*9356374aSAndroid Build Coastguard Worker if (n < 0 || n > *size) return false;
130*9356374aSAndroid Build Coastguard Worker *size -= n;
131*9356374aSAndroid Build Coastguard Worker *buf += n;
132*9356374aSAndroid Build Coastguard Worker return true;
133*9356374aSAndroid Build Coastguard Worker }
134*9356374aSAndroid Build Coastguard Worker
DefaultLogFilterAndPrefix(absl::LogSeverity,const char * file,int line,char ** buf,int * buf_size)135*9356374aSAndroid Build Coastguard Worker bool DefaultLogFilterAndPrefix(absl::LogSeverity, const char* file, int line,
136*9356374aSAndroid Build Coastguard Worker char** buf, int* buf_size) {
137*9356374aSAndroid Build Coastguard Worker DoRawLog(buf, buf_size, "[%s : %d] RAW: ", file, line);
138*9356374aSAndroid Build Coastguard Worker return true;
139*9356374aSAndroid Build Coastguard Worker }
140*9356374aSAndroid Build Coastguard Worker
141*9356374aSAndroid Build Coastguard Worker ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
142*9356374aSAndroid Build Coastguard Worker absl::base_internal::AtomicHook<LogFilterAndPrefixHook>
143*9356374aSAndroid Build Coastguard Worker log_filter_and_prefix_hook(DefaultLogFilterAndPrefix);
144*9356374aSAndroid Build Coastguard Worker ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
145*9356374aSAndroid Build Coastguard Worker absl::base_internal::AtomicHook<AbortHook> abort_hook;
146*9356374aSAndroid Build Coastguard Worker
147*9356374aSAndroid Build Coastguard Worker void RawLogVA(absl::LogSeverity severity, const char* file, int line,
148*9356374aSAndroid Build Coastguard Worker const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0);
RawLogVA(absl::LogSeverity severity,const char * file,int line,const char * format,va_list ap)149*9356374aSAndroid Build Coastguard Worker void RawLogVA(absl::LogSeverity severity, const char* file, int line,
150*9356374aSAndroid Build Coastguard Worker const char* format, va_list ap) {
151*9356374aSAndroid Build Coastguard Worker char buffer[kLogBufSize];
152*9356374aSAndroid Build Coastguard Worker char* buf = buffer;
153*9356374aSAndroid Build Coastguard Worker int size = sizeof(buffer);
154*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
155*9356374aSAndroid Build Coastguard Worker bool enabled = true;
156*9356374aSAndroid Build Coastguard Worker #else
157*9356374aSAndroid Build Coastguard Worker bool enabled = false;
158*9356374aSAndroid Build Coastguard Worker #endif
159*9356374aSAndroid Build Coastguard Worker
160*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_MIN_LOG_LEVEL
161*9356374aSAndroid Build Coastguard Worker if (severity < static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) &&
162*9356374aSAndroid Build Coastguard Worker severity < absl::LogSeverity::kFatal) {
163*9356374aSAndroid Build Coastguard Worker enabled = false;
164*9356374aSAndroid Build Coastguard Worker }
165*9356374aSAndroid Build Coastguard Worker #endif
166*9356374aSAndroid Build Coastguard Worker
167*9356374aSAndroid Build Coastguard Worker enabled = log_filter_and_prefix_hook(severity, file, line, &buf, &size);
168*9356374aSAndroid Build Coastguard Worker const char* const prefix_end = buf;
169*9356374aSAndroid Build Coastguard Worker
170*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
171*9356374aSAndroid Build Coastguard Worker if (enabled) {
172*9356374aSAndroid Build Coastguard Worker bool no_chop = VADoRawLog(&buf, &size, format, ap);
173*9356374aSAndroid Build Coastguard Worker if (no_chop) {
174*9356374aSAndroid Build Coastguard Worker DoRawLog(&buf, &size, "\n");
175*9356374aSAndroid Build Coastguard Worker } else {
176*9356374aSAndroid Build Coastguard Worker DoRawLog(&buf, &size, "%s", kTruncated);
177*9356374aSAndroid Build Coastguard Worker }
178*9356374aSAndroid Build Coastguard Worker AsyncSignalSafeWriteError(buffer, strlen(buffer));
179*9356374aSAndroid Build Coastguard Worker }
180*9356374aSAndroid Build Coastguard Worker #else
181*9356374aSAndroid Build Coastguard Worker static_cast<void>(format);
182*9356374aSAndroid Build Coastguard Worker static_cast<void>(ap);
183*9356374aSAndroid Build Coastguard Worker static_cast<void>(enabled);
184*9356374aSAndroid Build Coastguard Worker #endif
185*9356374aSAndroid Build Coastguard Worker
186*9356374aSAndroid Build Coastguard Worker // Abort the process after logging a FATAL message, even if the output itself
187*9356374aSAndroid Build Coastguard Worker // was suppressed.
188*9356374aSAndroid Build Coastguard Worker if (severity == absl::LogSeverity::kFatal) {
189*9356374aSAndroid Build Coastguard Worker abort_hook(file, line, buffer, prefix_end, buffer + kLogBufSize);
190*9356374aSAndroid Build Coastguard Worker abort();
191*9356374aSAndroid Build Coastguard Worker }
192*9356374aSAndroid Build Coastguard Worker }
193*9356374aSAndroid Build Coastguard Worker
194*9356374aSAndroid Build Coastguard Worker // Non-formatting version of RawLog().
195*9356374aSAndroid Build Coastguard Worker //
196*9356374aSAndroid Build Coastguard Worker // TODO(gfalcon): When string_view no longer depends on base, change this
197*9356374aSAndroid Build Coastguard Worker // interface to take its message as a string_view instead.
DefaultInternalLog(absl::LogSeverity severity,const char * file,int line,const std::string & message)198*9356374aSAndroid Build Coastguard Worker void DefaultInternalLog(absl::LogSeverity severity, const char* file, int line,
199*9356374aSAndroid Build Coastguard Worker const std::string& message) {
200*9356374aSAndroid Build Coastguard Worker RawLog(severity, file, line, "%.*s", static_cast<int>(message.size()),
201*9356374aSAndroid Build Coastguard Worker message.data());
202*9356374aSAndroid Build Coastguard Worker }
203*9356374aSAndroid Build Coastguard Worker
204*9356374aSAndroid Build Coastguard Worker } // namespace
205*9356374aSAndroid Build Coastguard Worker
AsyncSignalSafeWriteError(const char * s,size_t len)206*9356374aSAndroid Build Coastguard Worker void AsyncSignalSafeWriteError(const char* s, size_t len) {
207*9356374aSAndroid Build Coastguard Worker if (!len) return;
208*9356374aSAndroid Build Coastguard Worker absl::base_internal::ErrnoSaver errno_saver;
209*9356374aSAndroid Build Coastguard Worker #if defined(__EMSCRIPTEN__)
210*9356374aSAndroid Build Coastguard Worker // In WebAssembly, bypass filesystem emulation via fwrite.
211*9356374aSAndroid Build Coastguard Worker if (s[len - 1] == '\n') {
212*9356374aSAndroid Build Coastguard Worker // Skip a trailing newline character as emscripten_errn adds one itself.
213*9356374aSAndroid Build Coastguard Worker len--;
214*9356374aSAndroid Build Coastguard Worker }
215*9356374aSAndroid Build Coastguard Worker // emscripten_errn was introduced in 3.1.41 but broken in standalone mode
216*9356374aSAndroid Build Coastguard Worker // until 3.1.43.
217*9356374aSAndroid Build Coastguard Worker #if ABSL_INTERNAL_EMSCRIPTEN_VERSION >= 3001043
218*9356374aSAndroid Build Coastguard Worker emscripten_errn(s, len);
219*9356374aSAndroid Build Coastguard Worker #else
220*9356374aSAndroid Build Coastguard Worker char buf[kLogBufSize];
221*9356374aSAndroid Build Coastguard Worker if (len >= kLogBufSize) {
222*9356374aSAndroid Build Coastguard Worker len = kLogBufSize - 1;
223*9356374aSAndroid Build Coastguard Worker constexpr size_t trunc_len = sizeof(kTruncated) - 2;
224*9356374aSAndroid Build Coastguard Worker memcpy(buf + len - trunc_len, kTruncated, trunc_len);
225*9356374aSAndroid Build Coastguard Worker buf[len] = '\0';
226*9356374aSAndroid Build Coastguard Worker len -= trunc_len;
227*9356374aSAndroid Build Coastguard Worker } else {
228*9356374aSAndroid Build Coastguard Worker buf[len] = '\0';
229*9356374aSAndroid Build Coastguard Worker }
230*9356374aSAndroid Build Coastguard Worker memcpy(buf, s, len);
231*9356374aSAndroid Build Coastguard Worker _emscripten_err(buf);
232*9356374aSAndroid Build Coastguard Worker #endif
233*9356374aSAndroid Build Coastguard Worker #elif defined(ABSL_HAVE_SYSCALL_WRITE)
234*9356374aSAndroid Build Coastguard Worker // We prefer calling write via `syscall` to minimize the risk of libc doing
235*9356374aSAndroid Build Coastguard Worker // something "helpful".
236*9356374aSAndroid Build Coastguard Worker syscall(SYS_write, STDERR_FILENO, s, len);
237*9356374aSAndroid Build Coastguard Worker #elif defined(ABSL_HAVE_POSIX_WRITE)
238*9356374aSAndroid Build Coastguard Worker write(STDERR_FILENO, s, len);
239*9356374aSAndroid Build Coastguard Worker #elif defined(ABSL_HAVE_RAW_IO)
240*9356374aSAndroid Build Coastguard Worker _write(/* stderr */ 2, s, static_cast<unsigned>(len));
241*9356374aSAndroid Build Coastguard Worker #else
242*9356374aSAndroid Build Coastguard Worker // stderr logging unsupported on this platform
243*9356374aSAndroid Build Coastguard Worker (void)s;
244*9356374aSAndroid Build Coastguard Worker (void)len;
245*9356374aSAndroid Build Coastguard Worker #endif
246*9356374aSAndroid Build Coastguard Worker }
247*9356374aSAndroid Build Coastguard Worker
RawLog(absl::LogSeverity severity,const char * file,int line,const char * format,...)248*9356374aSAndroid Build Coastguard Worker void RawLog(absl::LogSeverity severity, const char* file, int line,
249*9356374aSAndroid Build Coastguard Worker const char* format, ...) {
250*9356374aSAndroid Build Coastguard Worker va_list ap;
251*9356374aSAndroid Build Coastguard Worker va_start(ap, format);
252*9356374aSAndroid Build Coastguard Worker RawLogVA(severity, file, line, format, ap);
253*9356374aSAndroid Build Coastguard Worker va_end(ap);
254*9356374aSAndroid Build Coastguard Worker }
255*9356374aSAndroid Build Coastguard Worker
RawLoggingFullySupported()256*9356374aSAndroid Build Coastguard Worker bool RawLoggingFullySupported() {
257*9356374aSAndroid Build Coastguard Worker #ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED
258*9356374aSAndroid Build Coastguard Worker return true;
259*9356374aSAndroid Build Coastguard Worker #else // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
260*9356374aSAndroid Build Coastguard Worker return false;
261*9356374aSAndroid Build Coastguard Worker #endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED
262*9356374aSAndroid Build Coastguard Worker }
263*9356374aSAndroid Build Coastguard Worker
264*9356374aSAndroid Build Coastguard Worker ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL
265*9356374aSAndroid Build Coastguard Worker absl::base_internal::AtomicHook<InternalLogFunction>
266*9356374aSAndroid Build Coastguard Worker internal_log_function(DefaultInternalLog);
267*9356374aSAndroid Build Coastguard Worker
RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func)268*9356374aSAndroid Build Coastguard Worker void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func) {
269*9356374aSAndroid Build Coastguard Worker log_filter_and_prefix_hook.Store(func);
270*9356374aSAndroid Build Coastguard Worker }
271*9356374aSAndroid Build Coastguard Worker
RegisterAbortHook(AbortHook func)272*9356374aSAndroid Build Coastguard Worker void RegisterAbortHook(AbortHook func) { abort_hook.Store(func); }
273*9356374aSAndroid Build Coastguard Worker
RegisterInternalLogFunction(InternalLogFunction func)274*9356374aSAndroid Build Coastguard Worker void RegisterInternalLogFunction(InternalLogFunction func) {
275*9356374aSAndroid Build Coastguard Worker internal_log_function.Store(func);
276*9356374aSAndroid Build Coastguard Worker }
277*9356374aSAndroid Build Coastguard Worker
278*9356374aSAndroid Build Coastguard Worker } // namespace raw_log_internal
279*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
280*9356374aSAndroid Build Coastguard Worker } // namespace absl
281