1/*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "core/frame/Console.h"
31
32#include "bindings/core/v8/ScriptCallStackFactory.h"
33#include "core/inspector/InspectorConsoleInstrumentation.h"
34#include "core/inspector/InspectorTraceEvents.h"
35#include "core/inspector/ScriptArguments.h"
36#include "platform/TraceEvent.h"
37#include "wtf/text/CString.h"
38#include "wtf/text/WTFString.h"
39
40namespace blink {
41
42ConsoleBase::~ConsoleBase()
43{
44}
45
46void ConsoleBase::debug(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
47{
48    internalAddMessage(LogMessageType, DebugMessageLevel, scriptState, arguments);
49}
50
51void ConsoleBase::error(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
52{
53    internalAddMessage(LogMessageType, ErrorMessageLevel, scriptState, arguments);
54}
55
56void ConsoleBase::info(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
57{
58    internalAddMessage(LogMessageType, InfoMessageLevel, scriptState, arguments);
59}
60
61void ConsoleBase::log(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
62{
63    internalAddMessage(LogMessageType, LogMessageLevel, scriptState, arguments);
64}
65
66void ConsoleBase::warn(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
67{
68    internalAddMessage(LogMessageType, WarningMessageLevel, scriptState, arguments);
69}
70
71void ConsoleBase::dir(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
72{
73    internalAddMessage(DirMessageType, LogMessageLevel, scriptState, arguments);
74}
75
76void ConsoleBase::dirxml(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
77{
78    internalAddMessage(DirXMLMessageType, LogMessageLevel, scriptState, arguments);
79}
80
81void ConsoleBase::table(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
82{
83    internalAddMessage(TableMessageType, LogMessageLevel, scriptState, arguments);
84}
85
86void ConsoleBase::clear(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
87{
88    internalAddMessage(ClearMessageType, LogMessageLevel, scriptState, arguments, true);
89}
90
91void ConsoleBase::trace(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
92{
93    internalAddMessage(TraceMessageType, LogMessageLevel, scriptState, arguments, true, true);
94}
95
96void ConsoleBase::assertCondition(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments, bool condition)
97{
98    if (condition)
99        return;
100
101    internalAddMessage(AssertMessageType, ErrorMessageLevel, scriptState, arguments, true);
102}
103
104void ConsoleBase::count(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
105{
106    RefPtrWillBeRawPtr<ScriptCallStack> callStack(createScriptCallStackForConsole(1));
107    const ScriptCallFrame& lastCaller = callStack->at(0);
108    // Follow Firebug's behavior of counting with null and undefined title in
109    // the same bucket as no argument
110    String title;
111    arguments->getFirstArgumentAsString(title);
112    String identifier = title.isEmpty() ? String(lastCaller.sourceURL() + ':' + String::number(lastCaller.lineNumber()))
113        : String(title + '@');
114
115    HashCountedSet<String>::AddResult result = m_counts.add(identifier);
116    String message = title + ": " + String::number(result.storedValue->value);
117
118    RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(ConsoleAPIMessageSource, DebugMessageLevel, message);
119    consoleMessage->setType(CountMessageType);
120    consoleMessage->setScriptState(scriptState);
121    consoleMessage->setCallStack(callStack.release());
122    reportMessageToConsole(consoleMessage.release());
123}
124
125void ConsoleBase::markTimeline(const String& title)
126{
127    timeStamp(title);
128}
129
130void ConsoleBase::profile(const String& title)
131{
132    InspectorInstrumentation::consoleProfile(context(), title);
133}
134
135void ConsoleBase::profileEnd(const String& title)
136{
137    InspectorInstrumentation::consoleProfileEnd(context(), title);
138}
139
140void ConsoleBase::time(const String& title)
141{
142    InspectorInstrumentation::consoleTime(context(), title);
143    TRACE_EVENT_COPY_ASYNC_BEGIN0("blink.console", title.utf8().data(), this);
144
145    if (title.isNull())
146        return;
147
148    m_times.add(title, monotonicallyIncreasingTime());
149}
150
151void ConsoleBase::timeEnd(ScriptState* scriptState, const String& title)
152{
153    TRACE_EVENT_COPY_ASYNC_END0("blink.console", title.utf8().data(), this);
154    InspectorInstrumentation::consoleTimeEnd(context(), title, scriptState);
155
156    // Follow Firebug's behavior of requiring a title that is not null or
157    // undefined for timing functions
158    if (title.isNull())
159        return;
160
161    HashMap<String, double>::iterator it = m_times.find(title);
162    if (it == m_times.end())
163        return;
164
165    double startTime = it->value;
166    m_times.remove(it);
167
168    double elapsed = monotonicallyIncreasingTime() - startTime;
169    String message = title + String::format(": %.3fms", elapsed * 1000);
170
171    RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(ConsoleAPIMessageSource, DebugMessageLevel, message);
172    consoleMessage->setType(TimeEndMessageType);
173    consoleMessage->setScriptState(scriptState);
174    consoleMessage->setCallStack(createScriptCallStackForConsole(1));
175    reportMessageToConsole(consoleMessage.release());
176}
177
178void ConsoleBase::timeStamp(const String& title)
179{
180    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "TimeStamp", "data", InspectorTimeStampEvent::data(context(), title));
181    // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
182    InspectorInstrumentation::consoleTimeStamp(context(), title);
183}
184
185static String formatTimelineTitle(const String& title)
186{
187    return String::format("Timeline '%s'", title.utf8().data());
188}
189
190void ConsoleBase::timeline(ScriptState* scriptState, const String& title)
191{
192    // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
193    InspectorInstrumentation::consoleTimeline(context(), title, scriptState);
194
195    TRACE_EVENT_COPY_ASYNC_BEGIN0("blink.console", formatTimelineTitle(title).utf8().data(), this);
196}
197
198void ConsoleBase::timelineEnd(ScriptState* scriptState, const String& title)
199{
200    // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
201    InspectorInstrumentation::consoleTimelineEnd(context(), title, scriptState);
202
203    TRACE_EVENT_COPY_ASYNC_END0("blink.console", formatTimelineTitle(title).utf8().data(), this);
204}
205
206void ConsoleBase::group(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
207{
208    internalAddMessage(StartGroupMessageType, LogMessageLevel, scriptState, arguments, true);
209}
210
211void ConsoleBase::groupCollapsed(ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> arguments)
212{
213    internalAddMessage(StartGroupCollapsedMessageType, LogMessageLevel, scriptState, arguments, true);
214}
215
216void ConsoleBase::groupEnd()
217{
218    internalAddMessage(EndGroupMessageType, LogMessageLevel, nullptr, nullptr, true);
219}
220
221void ConsoleBase::internalAddMessage(MessageType type, MessageLevel level, ScriptState* scriptState, PassRefPtrWillBeRawPtr<ScriptArguments> scriptArguments, bool acceptNoArguments, bool printTrace)
222{
223    RefPtrWillBeRawPtr<ScriptArguments> arguments = scriptArguments;
224    if (!acceptNoArguments && (!arguments || !arguments->argumentCount()))
225        return;
226
227    String message;
228    bool gotStringMessage = arguments ? arguments->getFirstArgumentAsString(message) : false;
229
230    RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(ConsoleAPIMessageSource, level, gotStringMessage? message : String());
231    consoleMessage->setType(type);
232    consoleMessage->setScriptState(scriptState);
233    consoleMessage->setScriptArguments(arguments);
234
235    size_t stackSize = printTrace ? ScriptCallStack::maxCallStackSizeToCapture : 1;
236    consoleMessage->setCallStack(createScriptCallStackForConsole(stackSize));
237    reportMessageToConsole(consoleMessage.release());
238}
239
240} // namespace blink
241