Permalink
Cannot retrieve contributors at this time
/* | |
* Copyright 2011 Google Inc. All Rights Reserved. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package com.google.walkaround.util.client.log; | |
import com.google.gwt.core.client.GWT; | |
import com.google.gwt.core.client.JsonUtils; | |
import com.google.gwt.xhr.client.XMLHttpRequest; | |
import com.google.walkaround.util.client.log.Logs.Handler; | |
import com.google.walkaround.util.client.log.Logs.Level; | |
/** | |
* A log handler that reports fatal logs to the server, and tees off warning | |
* logs to its subclass. | |
* | |
* @author danilatos@google.com (Daniel Danilatos) | |
*/ | |
public class ErrorReportingLogHandler implements Handler { | |
private boolean firstReport = true; | |
private final String errorReportUrl; | |
public ErrorReportingLogHandler(String errorReportUrl) { | |
this.errorReportUrl = errorReportUrl; | |
} | |
@Override | |
public boolean canReceive() { | |
return true; | |
} | |
@Override | |
public void receiveEntry( | |
int num, double timestamp, String stream, Level level, Object[] objects, Throwable t) { | |
if (level.compareTo(Level.SEVERE) <= 0) { | |
onSevere(stream); | |
report(timestamp, stream, level, objects, t); | |
} | |
} | |
/** | |
* Notifies a subclass of a severe log event on a stream. | |
*/ | |
protected void onSevere(String stream) { | |
} | |
void report(double timestamp, String streamName, Level level, Object[] objects, Throwable t) { | |
// TODO(danilatos): Use a JsoView to construct and then serialize, rather | |
// than string builder, unless it's too slow (might even be faster). | |
StringBuilder sb = new StringBuilder(); | |
sb.append("{\"strongName\" : "); | |
sb.append(escape(GWT.getPermutationStrongName())); | |
sb.append(",\"timestamp\" : "); | |
sb.append("" + (long) timestamp); | |
sb.append(",\"stream\" : "); | |
sb.append(escape(streamName)); | |
sb.append(",\"level\" : "); | |
sb.append(escape(level.name())); | |
// Stacktrace info of the first exception found, if any | |
if (t != null) { | |
sb.append(",\"exception\" : "); | |
buildExceptionJson(sb, t); | |
} | |
sb.append(",\"objects\" : ["); | |
boolean needsComma = false; | |
for (Object o : objects) { | |
if (needsComma) { | |
sb.append(","); | |
} else { | |
needsComma = true; | |
} | |
sb.append(escape(o != null ? o.toString() : "(null)")); | |
} | |
sb.append("]}"); | |
String jsonData = sb.toString(); | |
XMLHttpRequest xhr = XMLHttpRequest.create(); | |
xhr.open("POST", errorReportUrl + "?firstReport=" + firstReport); | |
firstReport = false; | |
xhr.send(jsonData); | |
} | |
public void buildExceptionJson(StringBuilder sb, Throwable t) { | |
sb.append("{\"name\" : "); | |
sb.append(escape(t.getClass().getName())); | |
sb.append(",\"message\" : "); | |
sb.append(escape(t.getMessage())); | |
sb.append(",\"stackTrace\" : ["); | |
boolean needsComma = false; | |
for (StackTraceElement e : t.getStackTrace()) { | |
if (needsComma) { | |
sb.append(","); | |
} else { | |
needsComma = true; | |
} | |
sb.append(escape(e.getMethodName())); | |
} | |
sb.append("]"); | |
if (t.getCause() != null) { | |
sb.append(",\"cause\" : "); | |
buildExceptionJson(sb, t.getCause()); | |
} | |
sb.append("}"); | |
} | |
String escape(String unescaped) { | |
// + "" to avoid null | |
return JsonUtils.escapeValue(unescaped != null ? unescaped : "(null)"); | |
} | |
} |