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); }