Add the option to use JSON rather than GWT RPC in remote logging
Review at http://gwt-code-reviews.appspot.com/830802
Review by: fredsa@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8778 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/logging/Logging.gwt.xml b/user/src/com/google/gwt/logging/Logging.gwt.xml
index a3cc387..4646c37 100644
--- a/user/src/com/google/gwt/logging/Logging.gwt.xml
+++ b/user/src/com/google/gwt/logging/Logging.gwt.xml
@@ -13,6 +13,7 @@
<!-- limitations under the License. -->
<module>
+ <inherits name='com.google.gwt.json.JSON'/>
<inherits name="com.google.gwt.logging.LogImpl"/>
<source path="client" />
<source path="shared" />
diff --git a/user/src/com/google/gwt/logging/client/JsonLogRecordClientUtil.java b/user/src/com/google/gwt/logging/client/JsonLogRecordClientUtil.java
new file mode 100644
index 0000000..b210533
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/JsonLogRecordClientUtil.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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.gwt.logging.client;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+import com.google.gwt.logging.shared.SerializableLogRecord;
+import com.google.gwt.logging.shared.SerializableThrowable;
+
+/**
+ * A set of functions to convert SerializableLogRecords into JSON strings.
+ * The corresponding functions to convert them back are in
+ * JsonLogRecordServerUtil.java. This class should only be used in client
+ * side code since it imports com.google.gwt.json.client classes.
+ * TODO(unnurg) once there is a unified JSON GWT library, combine this with
+ * JsonLogRecordServerUtil.
+ */
+public class JsonLogRecordClientUtil {
+
+ public static String serializableLogRecordAsJson(SerializableLogRecord slr) {
+ return serializableLogRecordAsJsonObject(slr).toString();
+ }
+
+ private static JSONString getJsonString(String s) {
+ if (s == null) {
+ return new JSONString("");
+ }
+ return new JSONString(s);
+ }
+
+ private static JSONObject serializableLogRecordAsJsonObject(
+ SerializableLogRecord slr) {
+ JSONObject obj = new JSONObject();
+ obj.put("level", getJsonString(slr.getLevel()));
+ obj.put("loggerName", getJsonString(slr.getLoggerName()));
+ obj.put("msg", getJsonString(slr.getMsg()));
+ if (slr.getTimestamp() != null) {
+ obj.put("timestamp", new JSONString(slr.getTimestamp().toString()));
+ }
+ obj.put("thrown", serializableThrowableAsJsonObject(slr.getThrown()));
+ return obj;
+ }
+
+ private static JSONObject serializableStackTraceElementAsJsonObject(
+ StackTraceElement e) {
+ JSONObject obj = new JSONObject();
+ if (e != null) {
+ obj.put("className", getJsonString(e.getClassName()));
+ obj.put("fileName", getJsonString(e.getFileName()));
+ obj.put("methodName", getJsonString(e.getMethodName()));
+ obj.put("lineNumber", getJsonString("" + e.getLineNumber()));
+ }
+ return obj;
+ }
+
+ private static JSONObject serializableThrowableAsJsonObject(
+ SerializableThrowable t) {
+ JSONObject obj = new JSONObject();
+ if (t != null) {
+ obj.put("message", getJsonString(t.getMessage()));
+ obj.put("cause", serializableThrowableAsJsonObject(t.getCause()));
+ StackTraceElement[] stackTrace = t.getStackTrace();
+ if (stackTrace != null && stackTrace.length > 0) {
+ JSONArray arr = new JSONArray();
+ for (int i = 0; i < stackTrace.length; i++) {
+ arr.set(i, serializableStackTraceElementAsJsonObject(stackTrace[i]));
+ }
+ obj.put("stackTrace", arr);
+ }
+ }
+ return obj;
+ }
+}
diff --git a/user/src/com/google/gwt/logging/server/JsonLogRecordServerUtil.java b/user/src/com/google/gwt/logging/server/JsonLogRecordServerUtil.java
new file mode 100644
index 0000000..2173ddf
--- /dev/null
+++ b/user/src/com/google/gwt/logging/server/JsonLogRecordServerUtil.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * 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.gwt.logging.server;
+
+import com.google.gwt.logging.shared.SerializableLogRecord;
+import com.google.gwt.logging.shared.SerializableThrowable;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+
+/**
+ * A set of functions to convert standard JSON strings into
+ * SerializableLogRecords. The corresponding functions to create the JSON
+ * strings are in JsonLogRecordClientUtil.java. This class should only be used
+ * in server side code since it imports org.json classes.
+ * TODO(unnurg) once there is a unified JSON GWT library, combine this with
+ * JsonLogRecordClientUtil.
+ */
+public class JsonLogRecordServerUtil {
+ public static SerializableLogRecord serializableLogRecordFromJson(
+ String jsonString) {
+ try {
+ JSONObject slr = new JSONObject(jsonString);
+ String level = slr.getString("level");
+ String loggerName = slr.getString("loggerName");
+ String msg = slr.getString("msg");
+ long timestamp = Long.parseLong(slr.getString("timestamp"));
+ SerializableThrowable thrown =
+ serializableThrowableFromJson(slr.getString("thrown"));
+ return new SerializableLogRecord(level, loggerName, msg, thrown, timestamp);
+ } catch (JSONException e) {
+ }
+ return null;
+ }
+
+ private static StackTraceElement serializableStackTraceElementFromJson(
+ String jsonString) {
+ try {
+ JSONObject ste = new JSONObject(jsonString);
+ String className = ste.getString("className");
+ String fileName = ste.getString("fileName");
+ String methodName = ste.getString("methodName");
+ int lineNumber = Integer.parseInt(ste.getString("lineNumber"));
+ return new StackTraceElement(className, methodName, fileName,
+ lineNumber);
+ } catch (JSONException e) {
+ }
+ return null;
+ }
+
+ private static SerializableThrowable serializableThrowableFromJson(
+ String jsonString) {
+ try {
+ JSONObject t = new JSONObject(jsonString);
+ String message = t.getString("message");
+ SerializableThrowable cause =
+ serializableThrowableFromJson(t.getString("cause"));
+ StackTraceElement[] stackTrace = null;
+ JSONArray st = t.getJSONArray("stackTrace");
+ if (st.length() > 0) {
+ stackTrace = new StackTraceElement[st.length()];
+ for (int i = 0; i < st.length(); i++) {
+ stackTrace[i] = serializableStackTraceElementFromJson(st.getString(i));
+ }
+ }
+ return new SerializableThrowable(message, cause, stackTrace);
+ } catch (JSONException e) {
+ }
+ return null;
+ }
+}
diff --git a/user/src/com/google/gwt/logging/shared/SerializableLogRecord.java b/user/src/com/google/gwt/logging/shared/SerializableLogRecord.java
index 28b5c65..92816f0 100644
--- a/user/src/com/google/gwt/logging/shared/SerializableLogRecord.java
+++ b/user/src/com/google/gwt/logging/shared/SerializableLogRecord.java
@@ -31,13 +31,9 @@
private String level;
private String loggerName = "";
private String msg;
- private long timestamp;
private SerializableThrowable thrown = null;
+ private long timestamp;
- protected SerializableLogRecord() {
- // for serialization
- }
-
/**
* Create a new SerializableLogRecord from a LogRecord.
*/
@@ -50,7 +46,28 @@
thrown = new SerializableThrowable(lr.getThrown());
}
}
-
+
+ public SerializableLogRecord(String level, String loggerName, String msg,
+ SerializableThrowable thrown, long timestamp) {
+ this.level = level;
+ this.loggerName = loggerName;
+ this.msg = msg;
+ this.timestamp = timestamp;
+ this.thrown = thrown;
+ }
+
+ protected SerializableLogRecord() {
+ // for serialization
+ }
+
+ public String getLevel() {
+ return level;
+ }
+
+ public String getLoggerName() {
+ return loggerName;
+ }
+
/**
* Create a new LogRecord from this SerializableLogRecord.
*/
@@ -63,4 +80,16 @@
}
return lr;
}
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public SerializableThrowable getThrown() {
+ return thrown;
+ }
+
+ public Long getTimestamp() {
+ return timestamp;
+ }
}
diff --git a/user/src/com/google/gwt/logging/shared/SerializableThrowable.java b/user/src/com/google/gwt/logging/shared/SerializableThrowable.java
index 5a90871..ebbe381 100644
--- a/user/src/com/google/gwt/logging/shared/SerializableThrowable.java
+++ b/user/src/com/google/gwt/logging/shared/SerializableThrowable.java
@@ -25,25 +25,44 @@
* subclasses will cause the client side JS to be very big.
*/
public class SerializableThrowable implements IsSerializable {
- private String message;
private SerializableThrowable cause = null;
+ private String message;
private StackTraceElement[] stackTrace;
-
- protected SerializableThrowable() {
- // for serialization
- }
/**
* Create a new SerializableThrowable from a Throwable.
*/
public SerializableThrowable(Throwable t) {
message = t.getMessage();
- stackTrace = t.getStackTrace();
if (t.getCause() != null) {
cause = new SerializableThrowable(t.getCause());
}
+ stackTrace = t.getStackTrace();
+ }
+
+ public SerializableThrowable(String message, SerializableThrowable cause,
+ StackTraceElement[] stackTrace) {
+ this.message = message;
+ this.cause = cause;
+ this.stackTrace = stackTrace;
+ }
+
+ protected SerializableThrowable() {
+ // for serialization
+ }
+
+ public SerializableThrowable getCause() {
+ return cause;
}
+ public String getMessage() {
+ return message;
+ }
+
+ public StackTraceElement[] getStackTrace() {
+ return stackTrace;
+ }
+
/**
* Create a new Throwable from this SerializableThrowable.
*/
diff --git a/user/src/com/google/gwt/requestfactory/client/RequestFactoryLogHandler.java b/user/src/com/google/gwt/requestfactory/client/RequestFactoryLogHandler.java
index 21a7252..7ae3819 100644
--- a/user/src/com/google/gwt/requestfactory/client/RequestFactoryLogHandler.java
+++ b/user/src/com/google/gwt/requestfactory/client/RequestFactoryLogHandler.java
@@ -16,6 +16,8 @@
package com.google.gwt.requestfactory.client;
+import com.google.gwt.logging.client.JsonLogRecordClientUtil;
+import com.google.gwt.logging.shared.SerializableLogRecord;
import com.google.gwt.requestfactory.shared.LoggingRequest;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.SyncResult;
@@ -87,16 +89,22 @@
if (closed || !isLoggable(record)) {
return;
}
-
if (record.getLoggerName().contains(ignoredLoggerSubstring)) {
return;
}
-
- Receiver<Long> loggingReceiver = new LoggingReceiver();
- requestProvider.getLoggingRequest().logMessage(
- record.getLevel().toString(),
- record.getLoggerName(),
- record.getMessage()).fire(loggingReceiver);
+ SerializableLogRecord slr = new SerializableLogRecord(record);
+ String json = JsonLogRecordClientUtil.serializableLogRecordAsJson(slr);
+ requestProvider.getLoggingRequest().logMessage(json).fire(
+ new Receiver<Boolean>() {
+ @Override
+ public void onSuccess(Boolean response, Set<SyncResult> syncResults) {
+ if (!response) {
+ // A separate logger for wire activity, which does not get logged
+ // by the remote log handler, so we avoid infinite loops.
+ Logger wireLogger = Logger.getLogger("WireActivityLogger");
+ wireLogger.severe("Remote Logging failed to parse JSON");
+ }
+ }
+ });
}
-
}
diff --git a/user/src/com/google/gwt/requestfactory/server/Logging.java b/user/src/com/google/gwt/requestfactory/server/Logging.java
index 86f490c..fff5ebd 100644
--- a/user/src/com/google/gwt/requestfactory/server/Logging.java
+++ b/user/src/com/google/gwt/requestfactory/server/Logging.java
@@ -16,7 +16,10 @@
package com.google.gwt.requestfactory.server;
-import java.util.logging.Level;
+import com.google.gwt.logging.server.JsonLogRecordServerUtil;
+import com.google.gwt.logging.shared.SerializableLogRecord;
+
+import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
@@ -25,20 +28,17 @@
*/
public class Logging {
private static Logger logger = Logger.getLogger(Logging.class.getName());
-
- public static Long logMessage(
- String levelString, String loggerName, String originalMessage) {
- Level level = Level.SEVERE;
- try {
- level = Level.parse(levelString);
- } catch (IllegalArgumentException e) {
- return 0L;
+
+ public static Boolean logMessage(String serializedLogRecordString) {
+ SerializableLogRecord slr =
+ JsonLogRecordServerUtil.serializableLogRecordFromJson(
+ serializedLogRecordString);
+ LogRecord lr = slr.getLogRecord();
+ if (lr == null) {
+ return false;
}
- String message = String.format("Client Side Logger: %s Message: %s",
- loggerName, originalMessage);
-
- logger.log(level, message);
- return 1L;
+ logger.log(lr);
+ return true;
}
private Long id = 0L;
diff --git a/user/src/com/google/gwt/requestfactory/shared/LoggingRequest.java b/user/src/com/google/gwt/requestfactory/shared/LoggingRequest.java
index 6455c1b..cf07757 100644
--- a/user/src/com/google/gwt/requestfactory/shared/LoggingRequest.java
+++ b/user/src/com/google/gwt/requestfactory/shared/LoggingRequest.java
@@ -25,11 +25,8 @@
@Service(Logging.class)
public interface LoggingRequest {
- // Should be returning something better than a Long, but that's all that is
- // supported for now, so using it as a boolean.
- // Should also be passing something better than a series of strings, but
- // that's the only possibility for now.
- RequestObject<Long> logMessage(
- String level, String loggerName, String message);
+ // TODO(unnurg): Pass a SerializableLogRecord here rather than it's
+ // serialized string.
+ RequestObject<Boolean> logMessage(String serializedLogRecordString);
}