LoggingInterface.h (3832B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 // An experimental logging interface for connecting the JS Engine to some 8 // (*cough*Gecko*cough*) consumer. 9 10 #ifndef _js_experimental_LoggingInterface_h_ 11 #define _js_experimental_LoggingInterface_h_ 12 13 #include "mozilla/LoggingCore.h" 14 15 #include "jstypes.h" 16 #include "fmt/format.h" 17 #include "js/GCAPI.h" 18 19 struct JSContext; 20 21 namespace JS { 22 23 // An Opaque pointer to a LoggerType. It must be possible for this logger type 24 // to conform to the interface below, using the LogLevel type exported in 25 // mozglue LoggingCore.h 26 // 27 // There are some requirements that we cannot express through the type-system: 28 // 29 // - A Logger must outlive any caller. This is an obvious statement, but in the 30 // context of the JS engine means that a logger must live until after the JS 31 // engine is shutdown. 32 // - A logger cannot move. The logging interfaces assumes 1) That an 33 // OpaqueLogger will remain a valid handle to a logger for the entire duration 34 // of an initialize JS library, and 2) We are able to cache a reference to the 35 // log level of a particular logger (see getLevelRef below). 36 using OpaqueLogger = void*; 37 38 // [SMDOC] Logging Interface 39 // 40 // The logging interface contains a set of function pointers which explain how 41 // to talk to an embedder provided logging system. 42 // 43 // The design of the JS Consumer of this relies heavily on these to be freely 44 // copyable. 45 struct LoggingInterface { 46 // Acquire a new logger for a given name. 47 // 48 // This interface has no way of indicating backwards that a logger is no 49 // longer needed, and as such this pointer needs to be kept alive by the 50 // embedding for the lifetime of the JS engine. 51 OpaqueLogger (*getLoggerByName)(const char* loggerName) = nullptr; 52 53 // Print a message to a particular logger with a particular level and 54 // format. 55 void (*logPrintVA)(const OpaqueLogger aModule, mozilla::LogLevel aLevel, 56 const char* aFmt, va_list ap) 57 MOZ_FORMAT_PRINTF(3, 0) = nullptr; 58 59 void (*logPrintFMT)(const OpaqueLogger aModule, mozilla::LogLevel aLevel, 60 fmt::string_view, fmt::format_args); 61 62 // Return a reference to the provided OpaqueLogger's level ref; Implementation 63 // wise this can be a small violation of encapsulation but is intended to help 64 // ensure that we can build lightweight logging without egregious costs to 65 // simply check even if a mesage will the writen 66 mozilla::AtomicLogLevel& (*getLevelRef)(OpaqueLogger) = nullptr; 67 68 // Wrapper function for calling va-version 69 void logPrint(const OpaqueLogger aModule, mozilla::LogLevel aLevel, 70 const char* aFmt, ...) MOZ_FORMAT_PRINTF(4, 5) { 71 JS::AutoSuppressGCAnalysis suppress; 72 va_list ap; 73 va_start(ap, aFmt); 74 this->logPrintVA(aModule, aLevel, aFmt, ap); 75 va_end(ap); 76 } 77 78 template <typename... T> 79 void logPrintFmt(const OpaqueLogger aModule, mozilla::LogLevel aLevel, 80 fmt::format_string<T...> aFmt, T&&... aArgs) { 81 JS::AutoSuppressGCAnalysis suppress; 82 this->logPrintFMT(aModule, aLevel, aFmt, fmt::make_format_args(aArgs...)); 83 } 84 85 // Used to ensure that before we use an interface, it's successfully been 86 // completely filled in. 87 bool isComplete() const { 88 return getLoggerByName && logPrintVA && getLevelRef; 89 } 90 }; 91 92 // Install the logging interface. This will also install the interface into 93 // any JS loggers 94 extern JS_PUBLIC_API bool SetLoggingInterface(LoggingInterface& iface); 95 96 } // namespace JS 97 98 #endif /* _js_experimental_LoggingInterface_h_ */