Bug 1880286 - Don't call SetLogLevel() after unlink. r=smaug
[gecko.git] / dom / console / ConsoleInstance.cpp
blob24477da56c06c0a9eb57de8abd4ce70702b918b4
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)) {
50 mConsole->mConsoleID = aOptions.mConsoleID;
51 mConsole->mPassedInnerID = aOptions.mInnerID;
53 if (aOptions.mDump.WasPassed()) {
54 mConsole->mDumpFunction = &aOptions.mDump.Value();
57 mConsole->mPrefix = aOptions.mPrefix;
59 // Let's inform that this is a custom instance.
60 mConsole->mChromeInstance = true;
62 if (aOptions.mMaxLogLevel.WasPassed()) {
63 mMaxLogLevel = aOptions.mMaxLogLevel.Value();
66 if (!aOptions.mMaxLogLevelPref.IsEmpty()) {
67 if (!NS_IsMainThread()) {
68 NS_WARNING("Console.maxLogLevelPref is not supported on workers!");
69 // Set the log level based on what we have.
70 SetLogLevel();
71 return;
74 CopyUTF16toUTF8(aOptions.mMaxLogLevelPref, mMaxLogLevelPref);
76 Preferences::RegisterCallback(MaxLogLevelPrefChangedCallback,
77 mMaxLogLevelPref, this);
79 SetLogLevel();
82 ConsoleInstance::~ConsoleInstance() {
83 AssertIsOnMainThread();
84 if (!mMaxLogLevelPref.IsEmpty()) {
85 Preferences::UnregisterCallback(MaxLogLevelPrefChangedCallback,
86 mMaxLogLevelPref, this);
90 ConsoleLogLevel PrefToValue(const nsACString& aPref,
91 const ConsoleLogLevel aLevel) {
92 if (aPref.IsEmpty()) {
93 return aLevel;
96 nsAutoCString value;
97 nsresult rv = Preferences::GetCString(PromiseFlatCString(aPref).get(), value);
98 if (NS_WARN_IF(NS_FAILED(rv))) {
99 nsString message;
100 message.AssignLiteral(
101 "Console.maxLogLevelPref used with a non-existing pref: ");
102 message.Append(NS_ConvertUTF8toUTF16(aPref));
104 nsContentUtils::LogSimpleConsoleError(message, "chrome"_ns, false,
105 true /* from chrome context*/);
106 return aLevel;
109 int index = FindEnumStringIndexImpl(value.get(), value.Length(),
110 ConsoleLogLevelValues::strings);
111 if (NS_WARN_IF(index < 0)) {
112 nsString message;
113 message.AssignLiteral("Invalid Console.maxLogLevelPref value: ");
114 message.Append(NS_ConvertUTF8toUTF16(value));
116 nsContentUtils::LogSimpleConsoleError(message, "chrome"_ns, false,
117 true /* from chrome context*/);
118 return aLevel;
121 MOZ_ASSERT(index < (int)ConsoleLogLevelValues::Count);
122 return static_cast<ConsoleLogLevel>(index);
125 void ConsoleInstance::SetLogLevel() {
126 mConsole->mCurrentLogLevel = mConsole->WebIDLLogLevelToInteger(
127 PrefToValue(mMaxLogLevelPref, mMaxLogLevel));
130 // static
131 void ConsoleInstance::MaxLogLevelPrefChangedCallback(
132 const char* /* aPrefName */, void* aSelf) {
133 AssertIsOnMainThread();
134 auto* instance = static_cast<ConsoleInstance*>(aSelf);
135 if (MOZ_UNLIKELY(!instance->mConsole)) {
136 // We've been unlinked already but not destroyed yet. Bail.
137 return;
139 RefPtr pin{instance};
140 pin->SetLogLevel();
143 JSObject* ConsoleInstance::WrapObject(JSContext* aCx,
144 JS::Handle<JSObject*> aGivenProto) {
145 return ConsoleInstance_Binding::Wrap(aCx, this, aGivenProto);
148 #define METHOD(name, string) \
149 void ConsoleInstance::name(JSContext* aCx, \
150 const Sequence<JS::Value>& aData) { \
151 RefPtr<Console> console(mConsole); \
152 console->MethodInternal(aCx, Console::Method##name, \
153 nsLiteralString(string), aData); \
156 METHOD(Log, u"log")
157 METHOD(Info, u"info")
158 METHOD(Warn, u"warn")
159 METHOD(Error, u"error")
160 METHOD(Exception, u"exception")
161 METHOD(Debug, u"debug")
162 METHOD(Table, u"table")
163 METHOD(Trace, u"trace")
164 METHOD(Dir, u"dir");
165 METHOD(Dirxml, u"dirxml");
166 METHOD(Group, u"group")
167 METHOD(GroupCollapsed, u"groupCollapsed")
169 #undef METHOD
171 void ConsoleInstance::GroupEnd(JSContext* aCx) {
172 const Sequence<JS::Value> data;
173 RefPtr<Console> console(mConsole);
174 console->MethodInternal(aCx, Console::MethodGroupEnd, u"groupEnd"_ns, data);
177 void ConsoleInstance::Time(JSContext* aCx, const nsAString& aLabel) {
178 RefPtr<Console> console(mConsole);
179 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
180 Console::MethodTime, u"time"_ns);
183 void ConsoleInstance::TimeLog(JSContext* aCx, const nsAString& aLabel,
184 const Sequence<JS::Value>& aData) {
185 RefPtr<Console> console(mConsole);
186 console->StringMethodInternal(aCx, aLabel, aData, Console::MethodTimeLog,
187 u"timeLog"_ns);
190 void ConsoleInstance::TimeEnd(JSContext* aCx, const nsAString& aLabel) {
191 RefPtr<Console> console(mConsole);
192 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
193 Console::MethodTimeEnd, u"timeEnd"_ns);
196 void ConsoleInstance::TimeStamp(JSContext* aCx,
197 const JS::Handle<JS::Value> aData) {
198 ConsoleCommon::ClearException ce(aCx);
200 Sequence<JS::Value> data;
201 SequenceRooter<JS::Value> rooter(aCx, &data);
203 if (aData.isString() && !data.AppendElement(aData, fallible)) {
204 return;
207 RefPtr<Console> console(mConsole);
208 console->MethodInternal(aCx, Console::MethodTimeStamp, u"timeStamp"_ns, data);
211 void ConsoleInstance::Profile(JSContext* aCx,
212 const Sequence<JS::Value>& aData) {
213 RefPtr<Console> console(mConsole);
214 console->ProfileMethodInternal(aCx, Console::MethodProfile, u"profile"_ns,
215 aData);
218 void ConsoleInstance::ProfileEnd(JSContext* aCx,
219 const Sequence<JS::Value>& aData) {
220 RefPtr<Console> console(mConsole);
221 console->ProfileMethodInternal(aCx, Console::MethodProfileEnd,
222 u"profileEnd"_ns, aData);
225 void ConsoleInstance::Assert(JSContext* aCx, bool aCondition,
226 const Sequence<JS::Value>& aData) {
227 if (!aCondition) {
228 RefPtr<Console> console(mConsole);
229 console->MethodInternal(aCx, Console::MethodAssert, u"assert"_ns, aData);
233 void ConsoleInstance::Count(JSContext* aCx, const nsAString& aLabel) {
234 RefPtr<Console> console(mConsole);
235 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
236 Console::MethodCount, u"count"_ns);
239 void ConsoleInstance::CountReset(JSContext* aCx, const nsAString& aLabel) {
240 RefPtr<Console> console(mConsole);
241 console->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
242 Console::MethodCountReset, u"countReset"_ns);
245 void ConsoleInstance::Clear(JSContext* aCx) {
246 const Sequence<JS::Value> data;
247 RefPtr<Console> console(mConsole);
248 console->MethodInternal(aCx, Console::MethodClear, u"clear"_ns, data);
251 bool ConsoleInstance::ShouldLog(ConsoleLogLevel aLevel) {
252 return mConsole->mCurrentLogLevel <=
253 mConsole->WebIDLLogLevelToInteger(aLevel);
256 void ConsoleInstance::ReportForServiceWorkerScope(const nsAString& aScope,
257 const nsAString& aMessage,
258 const nsAString& aFilename,
259 uint32_t aLineNumber,
260 uint32_t aColumnNumber,
261 ConsoleLevel aLevel) {
262 if (!NS_IsMainThread()) {
263 return;
266 ConsoleUtils::ReportForServiceWorkerScope(
267 aScope, aMessage, aFilename, aLineNumber, aColumnNumber,
268 WebIDLevelToConsoleUtilsLevel(aLevel));
271 } // namespace mozilla::dom