Update configs. IGNORE BROKEN CHANGESETS CLOSED TREE NO BUG a=release ba=release
[gecko.git] / dom / console / ConsoleInstance.cpp
blob22e0286feeb14190e22a74ee2585d0c0b330d182
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/. */
7 #include "mozilla/dom/ConsoleInstance.h"
8 #include "Console.h"
9 #include "mozilla/dom/ConsoleBinding.h"
10 #include "mozilla/Preferences.h"
11 #include "ConsoleCommon.h"
12 #include "ConsoleUtils.h"
13 #include "nsContentUtils.h"
15 namespace mozilla::dom {
17 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ConsoleInstance, mConsole)
19 NS_IMPL_CYCLE_COLLECTING_ADDREF(ConsoleInstance)
20 NS_IMPL_CYCLE_COLLECTING_RELEASE(ConsoleInstance)
22 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ConsoleInstance)
23 NS_INTERFACE_MAP_ENTRY(nsISupports)
24 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
25 NS_INTERFACE_MAP_END
27 namespace {
29 ConsoleUtils::Level WebIDLevelToConsoleUtilsLevel(ConsoleLevel aLevel) {
30 switch (aLevel) {
31 case ConsoleLevel::Log:
32 return ConsoleUtils::eLog;
33 case ConsoleLevel::Warning:
34 return ConsoleUtils::eWarning;
35 case ConsoleLevel::Error:
36 return ConsoleUtils::eError;
37 default:
38 break;
41 return ConsoleUtils::eLog;
44 } // namespace
46 ConsoleInstance::ConsoleInstance(JSContext* aCx,
47 const ConsoleInstanceOptions& aOptions)
48 : mMaxLogLevel(ConsoleLogLevel::All),
49 mConsole(new Console(aCx, nullptr, 0, 0, aOptions.mPrefix)) {
50 mConsole->mConsoleID = aOptions.mConsoleID;
51 mConsole->mPassedInnerID = aOptions.mInnerID;
53 if (aOptions.mDump.WasPassed()) {
54 mConsole->mDumpFunction = &aOptions.mDump.Value();
57 // Let's inform that this is a custom instance.
58 mConsole->mChromeInstance = true;
60 if (aOptions.mMaxLogLevel.WasPassed()) {
61 mMaxLogLevel = aOptions.mMaxLogLevel.Value();
64 if (!aOptions.mMaxLogLevelPref.IsEmpty()) {
65 if (!NS_IsMainThread()) {
66 // Set the log level based on what we have.
67 SetLogLevel();
69 // Flag an error to the console.
70 JS::Rooted<JS::Value> msg(aCx);
71 if (!ToJSValue(
72 aCx,
73 nsLiteralCString(
74 "Console.maxLogLevelPref is not supported within workers!"),
75 &msg)) {
76 JS_ClearPendingException(aCx);
77 return;
80 AutoTArray<JS::Value, 1> sequence;
81 SequenceRooter rootedSequence(aCx, &sequence);
82 sequence.AppendElement(std::move(msg));
83 this->Error(aCx, std::move(sequence));
84 return;
87 mMaxLogLevelPref = aOptions.mMaxLogLevelPref;
89 Preferences::RegisterCallback(MaxLogLevelPrefChangedCallback,
90 mMaxLogLevelPref, this);
92 SetLogLevel();
95 ConsoleInstance::~ConsoleInstance() {
96 // We should only ever have set `mMaxLogLevelPref` when on the main thread,
97 // but check it here to be safe.
98 if (!mMaxLogLevelPref.IsEmpty() && NS_IsMainThread()) {
99 Preferences::UnregisterCallback(MaxLogLevelPrefChangedCallback,
100 mMaxLogLevelPref, this);
104 ConsoleLogLevel PrefToValue(const nsACString& aPref,
105 const ConsoleLogLevel aLevel) {
106 if (aPref.IsEmpty()) {
107 return aLevel;
110 nsAutoCString value;
111 nsresult rv = Preferences::GetCString(PromiseFlatCString(aPref).get(), value);
112 if (NS_WARN_IF(NS_FAILED(rv))) {
113 nsString message;
114 message.AssignLiteral(
115 "Console.maxLogLevelPref used with a non-existing pref: ");
116 message.Append(NS_ConvertUTF8toUTF16(aPref));
118 nsContentUtils::LogSimpleConsoleError(message, "chrome"_ns, false,
119 true /* from chrome context*/);
120 return aLevel;
123 Maybe<ConsoleLogLevel> level = StringToEnum<ConsoleLogLevel>(value);
124 if (NS_WARN_IF(level.isNothing())) {
125 nsString message;
126 message.AssignLiteral("Invalid Console.maxLogLevelPref value: ");
127 message.Append(NS_ConvertUTF8toUTF16(value));
129 nsContentUtils::LogSimpleConsoleError(message, "chrome"_ns, false,
130 true /* from chrome context*/);
131 return aLevel;
134 return level.value();
137 void ConsoleInstance::SetLogLevel() {
138 mConsole->mCurrentLogLevel = mConsole->WebIDLLogLevelToInteger(
139 PrefToValue(mMaxLogLevelPref, mMaxLogLevel));
142 // static
143 void ConsoleInstance::MaxLogLevelPrefChangedCallback(
144 const char* /* aPrefName */, void* aSelf) {
145 auto* instance = static_cast<ConsoleInstance*>(aSelf);
146 if (MOZ_UNLIKELY(!instance->mConsole)) {
147 // We've been unlinked already but not destroyed yet. Bail.
148 return;
150 RefPtr pin{instance};
151 pin->SetLogLevel();
154 JSObject* ConsoleInstance::WrapObject(JSContext* aCx,
155 JS::Handle<JSObject*> aGivenProto) {
156 return ConsoleInstance_Binding::Wrap(aCx, this, aGivenProto);
159 #define METHOD(name, string) \
160 void ConsoleInstance::name(JSContext* aCx, \
161 const Sequence<JS::Value>& aData) { \
162 RefPtr<Console> console(mConsole); \
163 console->MethodInternal(aCx, Console::Method##name, \
164 nsLiteralString(string), aData); \
167 METHOD(Log, u"log")
168 METHOD(Info, u"info")
169 METHOD(Warn, u"warn")
170 METHOD(Error, u"error")
171 METHOD(Exception, u"exception")
172 METHOD(Debug, u"debug")
173 METHOD(Table, u"table")
174 METHOD(Trace, u"trace")
175 METHOD(Dir, u"dir");
176 METHOD(Dirxml, u"dirxml");
177 METHOD(Group, u"group")
178 METHOD(GroupCollapsed, u"groupCollapsed")
180 #undef METHOD
182 void ConsoleInstance::GroupEnd(JSContext* aCx) {
183 const Sequence<JS::Value> data;
184 RefPtr<Console> console(mConsole);
185 console->MethodInternal(aCx, Console::MethodGroupEnd, u"groupEnd"_ns, data);
188 void ConsoleInstance::Time(JSContext* aCx, const nsAString& aLabel) {
189 RefPtr<Console> console(mConsole);
190 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
191 Console::MethodTime, u"time"_ns);
194 void ConsoleInstance::TimeLog(JSContext* aCx, const nsAString& aLabel,
195 const Sequence<JS::Value>& aData) {
196 RefPtr<Console> console(mConsole);
197 console->StringMethodInternal(aCx, aLabel, aData, Console::MethodTimeLog,
198 u"timeLog"_ns);
201 void ConsoleInstance::TimeEnd(JSContext* aCx, const nsAString& aLabel) {
202 RefPtr<Console> console(mConsole);
203 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
204 Console::MethodTimeEnd, u"timeEnd"_ns);
207 void ConsoleInstance::TimeStamp(JSContext* aCx,
208 const JS::Handle<JS::Value> aData) {
209 ConsoleCommon::ClearException ce(aCx);
211 Sequence<JS::Value> data;
212 SequenceRooter<JS::Value> rooter(aCx, &data);
214 if (aData.isString() && !data.AppendElement(aData, fallible)) {
215 return;
218 RefPtr<Console> console(mConsole);
219 console->MethodInternal(aCx, Console::MethodTimeStamp, u"timeStamp"_ns, data);
222 void ConsoleInstance::Profile(JSContext* aCx,
223 const Sequence<JS::Value>& aData) {
224 RefPtr<Console> console(mConsole);
225 console->ProfileMethodInternal(aCx, Console::MethodProfile, u"profile"_ns,
226 aData);
229 void ConsoleInstance::ProfileEnd(JSContext* aCx,
230 const Sequence<JS::Value>& aData) {
231 RefPtr<Console> console(mConsole);
232 console->ProfileMethodInternal(aCx, Console::MethodProfileEnd,
233 u"profileEnd"_ns, aData);
236 void ConsoleInstance::Assert(JSContext* aCx, bool aCondition,
237 const Sequence<JS::Value>& aData) {
238 if (!aCondition) {
239 RefPtr<Console> console(mConsole);
240 console->MethodInternal(aCx, Console::MethodAssert, u"assert"_ns, aData);
244 void ConsoleInstance::Count(JSContext* aCx, const nsAString& aLabel) {
245 RefPtr<Console> console(mConsole);
246 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
247 Console::MethodCount, u"count"_ns);
250 void ConsoleInstance::CountReset(JSContext* aCx, const nsAString& aLabel) {
251 RefPtr<Console> console(mConsole);
252 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
253 Console::MethodCountReset, u"countReset"_ns);
256 void ConsoleInstance::Clear(JSContext* aCx) {
257 const Sequence<JS::Value> data;
258 RefPtr<Console> console(mConsole);
259 console->MethodInternal(aCx, Console::MethodClear, u"clear"_ns, data);
262 bool ConsoleInstance::ShouldLog(ConsoleLogLevel aLevel) {
263 return mConsole->mCurrentLogLevel <=
264 mConsole->WebIDLLogLevelToInteger(aLevel);
267 void ConsoleInstance::ReportForServiceWorkerScope(const nsAString& aScope,
268 const nsAString& aMessage,
269 const nsACString& aFilename,
270 uint32_t aLineNumber,
271 uint32_t aColumnNumber,
272 ConsoleLevel aLevel) {
273 if (!NS_IsMainThread()) {
274 return;
277 ConsoleUtils::ReportForServiceWorkerScope(
278 aScope, aMessage, aFilename, aLineNumber, aColumnNumber,
279 WebIDLevelToConsoleUtilsLevel(aLevel));
282 } // namespace mozilla::dom