Moving gwt logging over from the IO branch. Changed the gwt.logging
property to gwt.logging.enabled so that it doesn't conflict for projects
using the incubator which already defines gwt.logging

Review by: spoon@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8260 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
index d9dc1de..2281eae 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
@@ -303,7 +303,10 @@
       type = TreeLogger.ERROR;
     }
     // Log at the top level for visibility.
-    getLogger().log(type, message, e);
+    TreeLogger t = getLogger();
+    if (t != null) {
+      getLogger().log(type, message, e);
+    }
   }
 
   /**
diff --git a/user/src/com/google/gwt/logging/LogImpl.gwt.xml b/user/src/com/google/gwt/logging/LogImpl.gwt.xml
new file mode 100644
index 0000000..ddf32b1
--- /dev/null
+++ b/user/src/com/google/gwt/logging/LogImpl.gwt.xml
@@ -0,0 +1,17 @@
+<module>
+  <source path="impl" />
+  
+  <!-- Set up and handle the gwt.logging property -->
+  <define-property name="gwt.logging.enabled" values="TRUE, FALSE" />
+  <replace-with class="com.google.gwt.logging.impl.LoggerImplRegular">
+    <when-type-is class="com.google.gwt.logging.impl.LoggerImplNull"/>
+    <when-property-is name="gwt.logging.enabled" value="TRUE" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.impl.LevelImplRegular">
+    <when-type-is class="com.google.gwt.logging.impl.LevelImplNull"/>
+    <when-property-is name="gwt.logging.enabled" value="TRUE" />
+  </replace-with>
+  
+  <set-property name="gwt.logging.enabled" value="FALSE"/> 
+  
+</module>
\ No newline at end of file
diff --git a/user/src/com/google/gwt/logging/Logging.gwt.xml b/user/src/com/google/gwt/logging/Logging.gwt.xml
new file mode 100644
index 0000000..ee40d37
--- /dev/null
+++ b/user/src/com/google/gwt/logging/Logging.gwt.xml
@@ -0,0 +1,98 @@
+<!--                                                                        -->
+<!-- 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   -->
+<!-- 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. License for the specific language governing permissions and   -->
+<!-- limitations under the License.                                         -->
+
+<!-- regular expressions support.                                           -->
+<module>
+  <inherits name="com.google.gwt.logging.LogImpl"/>
+  
+  <replace-with class="com.google.gwt.logging.client.LogConfiguration.LogConfigurationImplRegular">
+    <when-type-is class="com.google.gwt.logging.client.LogConfiguration.LogConfigurationImplNull"/>
+    <when-property-is name="gwt.logging.enabled" value="TRUE" />
+  </replace-with>
+
+  
+  <!-- Set up and handle the gwt.logging.logLevel property -->
+  <define-property name="gwt.logging.logLevel" values="ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE" />
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.All">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="ALL" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.Finest">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="FINEST" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.Finer">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="FINER" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.Fine">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="FINE" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.Config">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="CONFIG" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.Info">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="INFO" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.Warning">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="WARNING" />
+  </replace-with>
+  <replace-with class="com.google.gwt.logging.client.DefaultLevel.Severe">
+    <when-type-is class="com.google.gwt.logging.client.DefaultLevel" />
+    <when-property-is name="gwt.logging.logLevel" value="SEVERE" />
+  </replace-with>
+  
+  
+  <!-- Set up and handle the gwt.logging.xxxHandler properties -->
+  <define-property name="gwt.logging.consoleHandler" values="ENABLED, DISABLED" />
+  <replace-with class="com.google.gwt.logging.client.NullLogHandler">
+    <when-type-is class="com.google.gwt.logging.client.ConsoleLogHandler" />
+    <when-property-is name="gwt.logging.consoleHandler" value="DISABLED" />
+  </replace-with>
+  <define-property name="gwt.logging.developmentModeHandler" values="ENABLED, DISABLED" />
+  <replace-with class="com.google.gwt.logging.client.NullLogHandler">
+    <when-type-is class="com.google.gwt.logging.client.DevelopmentModeLogHandler" />
+    <when-property-is name="gwt.logging.developmentModeHandler" value="DISABLED" />
+  </replace-with>
+  <define-property name="gwt.logging.firebugHandler" values="ENABLED, DISABLED" />
+  <replace-with class="com.google.gwt.logging.client.NullLogHandler">
+    <when-type-is class="com.google.gwt.logging.client.FirebugLogHandler" />
+    <when-property-is name="gwt.logging.firebugHandler" value="DISABLED" />
+  </replace-with>
+  <define-property name="gwt.logging.systemHandler" values="ENABLED, DISABLED" />
+  <replace-with class="com.google.gwt.logging.client.NullLogHandler">
+    <when-type-is class="com.google.gwt.logging.client.SystemLogHandler" />
+    <when-property-is name="gwt.logging.systemHandler" value="DISABLED" />
+  </replace-with>
+  <define-property name="gwt.logging.popupHandler" values="ENABLED, DISABLED" />
+  <replace-with class="com.google.gwt.logging.client.NullLoggingPopup">
+    <when-type-is class="com.google.gwt.logging.client.BasicLoggingPopup" />
+    <when-property-is name="gwt.logging.popupHandler" value="DISABLED" />
+  </replace-with>
+ 
+  <!-- Default values for all properties -->
+  <set-property name="gwt.logging.enabled" value="TRUE"/> 
+  <set-property name="gwt.logging.logLevel" value="INFO"/>
+  <set-property name="gwt.logging.consoleHandler" value="ENABLED" />
+  <set-property name="gwt.logging.developmentModeHandler" value="ENABLED" />
+  <set-property name="gwt.logging.firebugHandler" value="ENABLED" />
+  <set-property name="gwt.logging.popupHandler" value="ENABLED" />
+  <set-property name="gwt.logging.systemHandler" value="ENABLED" />
+  
+  <entry-point class="com.google.gwt.logging.client.LogConfiguration"/>
+</module>
\ No newline at end of file
diff --git a/user/src/com/google/gwt/logging/client/BasicLoggingPopup.java b/user/src/com/google/gwt/logging/client/BasicLoggingPopup.java
new file mode 100644
index 0000000..bb678bf
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/BasicLoggingPopup.java
@@ -0,0 +1,66 @@
+/*
+ * 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.user.client.ui.DialogBox;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+
+/**
+ * A simple popup to show log messages
+ */
+public class BasicLoggingPopup extends DialogBox {
+  private VerticalPanel v;
+
+  // TODO(unnurg): Make this into a popup that is less intrusive to the 
+  // running of the application.
+  public BasicLoggingPopup() {
+    super(false, false);
+    ScrollPanel s = new ScrollPanel();
+    v = new VerticalPanel();
+    s.setWidget(v);
+    s.setAlwaysShowScrollBars(true);
+    s.setHeight("100px");
+    super.setWidget(s);
+    setText("Logging");
+    Button ok = new Button("OK");
+    ok.addClickHandler(new ClickHandler() {
+      public void onClick(ClickEvent event) {
+         hide();
+      }
+    });
+    v.add(ok);
+    show();
+  }
+  
+  @Override
+  public void add(Widget w) {
+    v.add(w);
+  }
+  
+  @Override
+  public void setWidget(Widget w) {
+    v.clear();
+    v.add(w);
+  }
+  
+
+}
diff --git a/user/src/com/google/gwt/logging/client/ConsoleLogHandler.java b/user/src/com/google/gwt/logging/client/ConsoleLogHandler.java
new file mode 100644
index 0000000..c8a1853
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/ConsoleLogHandler.java
@@ -0,0 +1,66 @@
+/*
+ * 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 java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * A Handler that prints logs to the window.console - this is used by things
+ * like FirebugLite in IE, and Safari debug mode.
+ * Note we are consciously using 'window' rather than '$wnd' to avoid issues
+ * similar to http://code.google.com/p/fbug/issues/detail?id=2914
+ */
+public class ConsoleLogHandler extends Handler {
+
+  public ConsoleLogHandler() {
+    setFormatter(new TextLogFormatter());
+    setLevel(Level.ALL);
+  }
+  
+  @Override
+  public void close() {
+    // No action needed
+  }
+
+  @Override
+  public void flush() {
+    // No action needed
+  }
+
+  @Override
+  public void publish(LogRecord record) {
+    if (!isSupported() || !isLoggable(record)) {
+      return;
+    }
+    String msg = getFormatter().format(record);
+    log(msg);
+  }
+
+  private native boolean isSupported() /*-{
+    return ((window.console != null) &&
+            (window.console.firebug == null) && 
+            (window.console.log != null) &&
+            (typeof(window.console.log) == 'function'));
+  }-*/;
+
+  private native void log(String message) /*-{
+    window.console.log(message);
+  }-*/;
+
+}
diff --git a/user/src/com/google/gwt/logging/client/DefaultLevel.java b/user/src/com/google/gwt/logging/client/DefaultLevel.java
new file mode 100644
index 0000000..c25bd47
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/DefaultLevel.java
@@ -0,0 +1,101 @@
+/*
+ * 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 java.util.logging.Level;
+
+/**
+ * An interface for a set of classes which are used to choose the default
+ * logging level. This allows the user to configure the default level in the
+ * gwt.xml file.
+ */
+public interface DefaultLevel {
+  /**
+   * Returns Level.ALL as the default level
+   */
+  public class All implements DefaultLevel {
+    public Level getLevel() {
+      return Level.ALL;
+    }
+  }
+
+  /**
+   * Returns Level.CONFIG as the default level
+   */
+  public class Config implements DefaultLevel {
+    public Level getLevel() {
+      return Level.CONFIG;
+    }
+  }
+
+  /**
+   * Returns Level.FINE as the default level
+   */
+  public class Fine implements DefaultLevel {
+    public Level getLevel() {
+      return Level.FINE;
+    }
+  }
+
+  /**
+   * Returns Level.FINER as the default level
+   */
+  public class Finer implements DefaultLevel {
+    public Level getLevel() {
+      return Level.FINER;
+    }
+  }
+
+  /**
+   * Returns Level.FINEST as the default level
+   */
+  public class Finest implements DefaultLevel {
+    public Level getLevel() {
+      return Level.FINEST;
+    }
+  }
+
+  /**
+   * Returns Level.INFO as the default level
+   */
+  public class Info implements DefaultLevel {
+    public Level getLevel() {
+      return Level.INFO;
+    }
+  }
+
+  /**
+   * Returns Level.SEVERE as the default level
+   */
+  public class Severe implements DefaultLevel {
+    public Level getLevel() {
+      return Level.SEVERE;
+    }
+  }
+
+  /**
+   * Returns Level.WARNING as the default level
+   */
+  public class Warning implements DefaultLevel {
+    public Level getLevel() {
+      return Level.WARNING;
+    }
+  }
+
+  Level getLevel();
+
+}
diff --git a/user/src/com/google/gwt/logging/client/DevelopmentModeLogHandler.java b/user/src/com/google/gwt/logging/client/DevelopmentModeLogHandler.java
new file mode 100644
index 0000000..188fdcb
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/DevelopmentModeLogHandler.java
@@ -0,0 +1,61 @@
+/*
+ * 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.core.client.GWT;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * A Handler that prints logs to GWT.log, causing the messages to show up in
+ * the Development Mode tab in Eclipse when running in Development mode.
+ */
+public class DevelopmentModeLogHandler extends Handler {
+  
+  public DevelopmentModeLogHandler() {
+    setFormatter(new TextLogFormatter());
+    setLevel(Level.ALL);
+  }
+
+  @Override
+  public void close() {
+    // No action needed
+  }
+
+  @Override
+  public void flush() {
+    // No action needed
+  }
+
+  @Override
+  public void publish(LogRecord record) {
+    if (!isSupported() || !isLoggable(record)) {
+      return;
+    }
+
+    // TODO(unnurg): pass in the throwable here since GWT.log can handle it
+    String msg = getFormatter().format(record);
+    GWT.log(msg);
+  }
+  
+  private boolean isSupported() {
+    return !GWT.isScript();
+  }
+
+}
diff --git a/user/src/com/google/gwt/logging/client/FirebugLogHandler.java b/user/src/com/google/gwt/logging/client/FirebugLogHandler.java
new file mode 100644
index 0000000..bffd9be
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/FirebugLogHandler.java
@@ -0,0 +1,83 @@
+/*
+ * 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 java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * A Handler that prints logs to window.console which is used by Firebug
+ * Note we are consciously using 'window' rather than '$wnd' to avoid issues
+ * similar to http://code.google.com/p/fbug/issues/detail?id=2914
+ */
+public class FirebugLogHandler extends Handler {
+  
+  public FirebugLogHandler() {
+    setFormatter(new TextLogFormatter());
+    setLevel(Level.ALL);  
+  }
+
+  @Override
+  public void close() {
+    // No action needed
+  }
+
+  @Override
+  public void flush() {
+    // No action needed
+  }
+
+  @Override
+  public void publish(LogRecord record) {
+    if (!isSupported() || !isLoggable(record)) {
+      return;
+    }
+    String msg = getFormatter().format(record);
+    int val = record.getLevel().intValue();
+    if (val <= Level.FINE.intValue()) {
+      debug(msg);
+    } else if (val < Level.WARNING.intValue()) {
+      info(msg);
+    } else if (val < Level.SEVERE.intValue()) {
+      warn(msg);
+    } else {
+      error(msg);
+    }
+  }
+  
+  private native void debug(String message) /*-{
+    window.console.debug(message);
+  }-*/;
+
+  private native void error(String message) /*-{
+    window.console.error(message);
+  }-*/;
+
+  private native void info(String message) /*-{
+    window.console.info(message);
+  }-*/;
+
+  private native boolean isSupported() /*-{
+    return !!(window.console && window.console.firebug);
+  }-*/;
+
+  private native void warn(String message) /*-{
+    window.console.warn(message);
+  }-*/;
+
+}
diff --git a/user/src/com/google/gwt/logging/client/HasWidgetsLogHandler.java b/user/src/com/google/gwt/logging/client/HasWidgetsLogHandler.java
new file mode 100644
index 0000000..7e6d062
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/HasWidgetsLogHandler.java
@@ -0,0 +1,76 @@
+/*
+ * 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.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.Label;
+
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * A handler which can log to any widget which extends the HasWidgets interface.
+ * This allows users to log to anywhere they would like in their UI - see the
+ * LogConfiguration class for an example. Note that the widget passed in must
+ * handle multiple calls to widget.add(widget) gracefully.
+ */
+public class HasWidgetsLogHandler extends Handler {
+
+  private HasWidgets widgetContainer;
+
+  public HasWidgetsLogHandler(HasWidgets container) {
+    this.widgetContainer = container;
+    setFormatter(new HtmlLogFormatter());
+    setLevel(Level.ALL);
+  }
+
+  public void clear() {
+    widgetContainer.clear();
+  }
+
+  @Override
+  public void close() {
+    // Do nothing
+  }
+
+  @Override
+  public void flush() {
+    // Do nothing
+  }
+
+  @Override
+  public void publish(LogRecord record) {
+    if (!isLoggable(record)) {
+      return;
+    }
+    Formatter formatter = getFormatter();
+    String msg = formatter.format(record);
+    // We want to make sure that unescaped messages are not output as HTML to
+    // the window and the HtmlLogFormatter ensures this. If you want to write a
+    // new formatter, subclass HtmlLogFormatter and override the getHtmlPrefix
+    // and getHtmlSuffix methods.
+    if (formatter instanceof HtmlLogFormatter) {
+      widgetContainer.add(new HTML(msg));
+    } else {
+      widgetContainer.add(new Label(msg));
+    }
+  }
+}
+
diff --git a/user/src/com/google/gwt/logging/client/HtmlLogFormatter.java b/user/src/com/google/gwt/logging/client/HtmlLogFormatter.java
new file mode 100644
index 0000000..c7d054f
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/HtmlLogFormatter.java
@@ -0,0 +1,64 @@
+/*
+ * 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 java.util.Date;
+import java.util.logging.Formatter;
+import java.util.logging.LogRecord;
+
+/**
+ * Formats LogRecords into HTML. Subclasses should override the GetHtmlPrefix
+ * and GetHtmlSuffix methods rather than format to ensure that the message
+ * is properly escaped.
+ */
+public class HtmlLogFormatter extends Formatter {
+
+  // TODO(unnurg): Handle the outputting of Throwables.
+  @Override
+  public String format(LogRecord event) {
+    StringBuilder html = new StringBuilder(getHtmlPrefix(event));
+    html.append(getEscapedMessage(event));
+    html.append(getHtmlSuffix(event));
+    return html.toString();
+  }
+  
+  protected String getHtmlPrefix(LogRecord event) {
+    Date date = new Date(event.getMillis());
+    StringBuilder prefix = new StringBuilder();
+    prefix.append("<code>");
+    prefix.append(date.toString());
+    prefix.append(" ");
+    prefix.append(event.getLoggerName());
+    prefix.append("<br/>");
+    prefix.append(event.getLevel().getName());
+    prefix.append(": ");
+    return prefix.toString();
+  }
+  
+  protected String getHtmlSuffix(LogRecord event) {
+    // TODO(unnurg): output throwables correctly
+    return "</code>";
+  }
+  
+  // TODO(unnurg): There must be a cleaner way to do this...
+  private String getEscapedMessage(LogRecord event) {
+    String text = event.getMessage();
+    text = text.replaceAll("<", "&lt;");
+    text = text.replaceAll(">", "&gt;");
+    return text;
+  }
+}
diff --git a/user/src/com/google/gwt/logging/client/LogConfiguration.java b/user/src/com/google/gwt/logging/client/LogConfiguration.java
new file mode 100644
index 0000000..fd88112
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/LogConfiguration.java
@@ -0,0 +1,127 @@
+/*
+ * 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.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Window.Location;
+import com.google.gwt.user.client.ui.HasWidgets;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Configures client side logging using the query params and gwt.xml settings.
+ */
+public class LogConfiguration implements EntryPoint {
+  
+  private interface LogConfigurationImpl {
+    void configureClientSideLogging();
+  }
+  
+  /** 
+   * Implementation which does nothing and compiles out if logging is disabled.
+   */
+  private static class LogConfigurationImplNull
+  implements LogConfigurationImpl {
+    public void configureClientSideLogging() { }
+  }
+  
+  /** 
+   * Implementation which is used when logging is enabled.
+   */
+  private static class LogConfigurationImplRegular
+  implements LogConfigurationImpl {
+  
+    public void configureClientSideLogging() {
+      Logger root = Logger.getLogger("");
+      setLevels(root);
+      setDefaultHandlers(root);
+    }
+  
+    private void addHandlerIfNotNull(Logger l, Handler h) {
+      if (!(h instanceof NullLogHandler)) {
+        l.addHandler(h);
+      }
+    }
+   
+    private Level parseLevel(String s) {
+      if (s == null) {
+        return null;
+      }
+      if (s.equals(Level.OFF.getName())) {
+        return Level.OFF;
+      } else if (s.equals(Level.SEVERE.getName())) {
+        return Level.SEVERE;
+      } else if (s.equals(Level.WARNING.getName())) {
+        return Level.WARNING;
+      } else if (s.equals(Level.INFO.getName())) {
+        return Level.INFO;
+      } else if (s.equals(Level.CONFIG.getName())) {
+        return Level.CONFIG;
+      } else if (s.equals(Level.FINE.getName())) {
+        return Level.FINE;
+      } else if (s.equals(Level.FINER.getName())) {
+        return Level.FINER;
+      } else if (s.equals(Level.FINEST.getName())) {
+        return Level.FINEST;
+      } else if (s.equals(Level.ALL.getName())) {
+        return Level.ALL;
+      }
+      return null;
+    }
+    
+    private void setDefaultHandlers(Logger l) {
+      // Add the default handlers. If users want some of these disabled, they
+      // will specify that in the gwt.xml file, which will replace the handler
+      // with an instance of NullLogHandler, effectively disabling it.
+      Handler console = GWT.create(ConsoleLogHandler.class);
+      addHandlerIfNotNull(l, console);
+      Handler dev = GWT.create(DevelopmentModeLogHandler.class);
+      addHandlerIfNotNull(l, dev);
+      Handler firebug = GWT.create(FirebugLogHandler.class);
+      addHandlerIfNotNull(l, firebug);
+      Handler system = GWT.create(SystemLogHandler.class);
+      addHandlerIfNotNull(l, system);
+      HasWidgets loggingWidget = GWT.create(BasicLoggingPopup.class);
+      if (!(loggingWidget instanceof NullLoggingPopup)) {
+        addHandlerIfNotNull(l, new HasWidgetsLogHandler(loggingWidget));
+      }
+    }
+  
+    private void setLevels(Logger l) {
+      // try to pull the log level from the query param
+      Level paramLevel = parseLevel(Location.getParameter("logLevel"));
+      if (paramLevel != null) {
+        l.setLevel(paramLevel);
+      } else {
+        // if it isn't there, then pull it from the gwt.xml file
+        DefaultLevel defaultLevel = GWT.create(DefaultLevel.class);
+        l.setLevel(defaultLevel.getLevel());
+      }
+    }
+  }
+  
+  private static LogConfigurationImpl impl =
+    GWT.create(LogConfigurationImplNull.class);
+
+  public void onModuleLoad() {
+    impl.configureClientSideLogging();
+  }
+
+}
diff --git a/user/src/com/google/gwt/logging/client/NullLogHandler.java b/user/src/com/google/gwt/logging/client/NullLogHandler.java
new file mode 100644
index 0000000..af6bfee
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/NullLogHandler.java
@@ -0,0 +1,38 @@
+/*
+ * 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 java.util.logging.Handler;
+import java.util.logging.LogRecord;
+
+/**
+ * A Handler which does nothing. When clients disable a default log handler in
+ * their gwt.xml file, the handler gets replaced with this one, and is
+ * effectively disabled.
+ */
+public class NullLogHandler extends Handler {
+
+  @Override
+  public void close() {  }
+
+  @Override
+  public void flush() {  }
+
+  @Override
+  public void publish(LogRecord record) {  }
+
+}
diff --git a/user/src/com/google/gwt/logging/client/NullLoggingPopup.java b/user/src/com/google/gwt/logging/client/NullLoggingPopup.java
new file mode 100644
index 0000000..e84513b
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/NullLoggingPopup.java
@@ -0,0 +1,42 @@
+/*
+ * 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.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.Widget;
+
+import java.util.Iterator;
+
+/**
+ * A class which can be substituted in for the BasicLoggingPopup in the
+ * the gwt.xml file to disable the default popup log handler.
+ */
+public class NullLoggingPopup implements HasWidgets {
+
+  public void add(Widget w) { }
+
+  public void clear() { }
+
+  public Iterator<Widget> iterator() {
+    return null;
+  }
+
+  public boolean remove(Widget w) {
+    return false;
+  }
+
+}
diff --git a/user/src/com/google/gwt/logging/client/SystemLogHandler.java b/user/src/com/google/gwt/logging/client/SystemLogHandler.java
new file mode 100644
index 0000000..1a35ff2
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/SystemLogHandler.java
@@ -0,0 +1,62 @@
+/*
+ * 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.core.client.GWT;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * A Handler that prints logs to System.out or System.err
+ */
+public class SystemLogHandler extends Handler {
+
+  public SystemLogHandler() {
+    setFormatter(new TextLogFormatter());
+    setLevel(Level.ALL);
+  }
+  
+  @Override
+  public void close() {
+    // No action needed
+  }
+
+  @Override
+  public void flush() {
+    // No action needed
+  }
+
+  @Override
+  public void publish(LogRecord record) {
+    if (!isSupported() || !isLoggable(record)) {
+      return;
+    }
+    String msg = getFormatter().format(record);
+    int val = record.getLevel().intValue();
+    if (val <= Level.WARNING.intValue()) {
+      System.out.println(msg);
+    } else {
+      System.err.println(msg);
+    }
+  }
+  
+  private boolean isSupported() {
+    return !GWT.isScript();
+  }
+}
diff --git a/user/src/com/google/gwt/logging/client/TextLogFormatter.java b/user/src/com/google/gwt/logging/client/TextLogFormatter.java
new file mode 100644
index 0000000..183d5b1
--- /dev/null
+++ b/user/src/com/google/gwt/logging/client/TextLogFormatter.java
@@ -0,0 +1,44 @@
+/*
+ * 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 java.util.Date;
+import java.util.logging.Formatter;
+import java.util.logging.LogRecord;
+
+/**
+ * Formats LogRecords into 2 lines of text
+ */
+public class TextLogFormatter extends Formatter {
+
+  @Override
+  public String format(LogRecord event) {
+    Date date = new Date(event.getMillis());
+    StringBuilder message = new StringBuilder();
+    message.append(date.toString());
+    message.append(" ");
+    message.append(event.getLoggerName());
+    message.append("\n");
+    message.append(event.getLevel().getName());
+    message.append(": ");
+    message.append(event.getMessage());
+    if (event.getThrown() != null) {
+      // TODO(unnurg): output throwables correctly
+    }
+    return message.toString();
+  }
+}
diff --git a/user/src/com/google/gwt/logging/impl/LevelImpl.java b/user/src/com/google/gwt/logging/impl/LevelImpl.java
new file mode 100644
index 0000000..f1a8426
--- /dev/null
+++ b/user/src/com/google/gwt/logging/impl/LevelImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.impl;
+
+import java.util.logging.Level;
+
+/**
+ * Interface for the implementation of Level. We use a LevelImplNull to ensure
+ * that logging code compiles out when logging is disabled, and a
+ * LevelImplRegular to provide normal functionality when logging is enabled.
+ */
+public interface LevelImpl {
+  Level all();
+  Level config();
+  Level fine();
+  Level finer();
+  Level finest();
+  String getName();
+  Level info();
+  int  intValue();
+  Level off();
+  void setName(String newName);
+  void setValue(int newValue);
+  Level severe();
+  String toString();
+  Level warning();
+}
diff --git a/user/src/com/google/gwt/logging/impl/LevelImplNull.java b/user/src/com/google/gwt/logging/impl/LevelImplNull.java
new file mode 100644
index 0000000..c202711
--- /dev/null
+++ b/user/src/com/google/gwt/logging/impl/LevelImplNull.java
@@ -0,0 +1,77 @@
+/*
+ * 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.impl;
+
+import java.util.logging.Level;
+
+/**
+ * Null implementation for the Level class which ensures that calls to Level
+ * compile out when logging is disabled.
+ */
+public class LevelImplNull implements LevelImpl {
+
+  public Level all() {
+    return null;
+  }
+
+  public Level config() {
+    return null;
+  }
+
+  public Level fine() {
+    return null;
+  }
+
+  public Level finer() {
+    return null;
+  }
+
+  public Level finest() {
+    return null;
+  }
+
+  public String getName() {
+    return null;
+  }
+
+  public Level info() {
+    return null;
+  }
+
+  public int intValue() {
+    return 0;
+  }
+
+  public Level off() {
+    return null;
+  }
+
+  public void setName(String newName) {
+  }
+
+  public void setValue(int newValue) {
+  }
+
+  public Level severe() {
+    return null;
+  }
+
+  public Level warning() {
+    return null;
+  }
+
+}
diff --git a/user/src/com/google/gwt/logging/impl/LevelImplRegular.java b/user/src/com/google/gwt/logging/impl/LevelImplRegular.java
new file mode 100644
index 0000000..f2a8e30
--- /dev/null
+++ b/user/src/com/google/gwt/logging/impl/LevelImplRegular.java
@@ -0,0 +1,116 @@
+/*
+ * 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.impl;
+
+import java.util.logging.Level;
+
+/**
+ * Implementation for the Level class when logging is enabled.
+ */
+public class LevelImplRegular implements LevelImpl {
+  
+  /** 
+   * Since the Impl class is in a different package than the Level class, we
+   * need to work around the fact that the Impl class cannot access the
+   * protected Level constructor.
+   */
+  private static class LevelWithExposedConstructor extends Level {
+    public LevelWithExposedConstructor(String name, int value) {
+      super(name, value);
+    }
+  }
+
+  private static Level ALL = 
+    new LevelWithExposedConstructor("ALL", Integer.MIN_VALUE); 
+  private static Level CONFIG =
+    new LevelWithExposedConstructor("CONFIG", 700); 
+  private static Level FINE =
+    new LevelWithExposedConstructor("FINE", 500); 
+  private static Level FINER =
+    new LevelWithExposedConstructor("FINER", 400); 
+  private static Level FINEST =
+    new LevelWithExposedConstructor("FINEST", 300); 
+  private static Level INFO =
+    new LevelWithExposedConstructor("INFO", 800); 
+  private static Level OFF =
+    new LevelWithExposedConstructor("OFF", Integer.MAX_VALUE); 
+  private static Level SEVERE =
+    new LevelWithExposedConstructor("SEVERE", 1000);
+  private static Level WARNING =
+    new LevelWithExposedConstructor("WARNING", 900); 
+  
+  private String name;
+  private int value;
+
+  public LevelImplRegular() { }
+  
+  public Level all() {
+    return LevelImplRegular.ALL;
+  }
+  
+  public Level config() {
+    return LevelImplRegular.CONFIG;
+  }
+    
+  public Level fine() {
+    return LevelImplRegular.FINE;
+  }
+  
+  public Level finer() {
+    return LevelImplRegular.FINER;
+  }
+  
+  public Level finest() {
+    return LevelImplRegular.FINEST;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public Level info() {
+    return LevelImplRegular.INFO;
+  }
+
+  public int intValue() {
+    return value;
+  }
+
+  public Level off() {
+    return LevelImplRegular.OFF;
+  }
+
+  public void setName(String newName) {
+    name = newName;
+  }
+
+  public void setValue(int newValue) {
+    value = newValue;
+  }
+
+  public Level severe() {
+    return LevelImplRegular.SEVERE;
+  }
+
+  public String toString() {
+    return getName();
+  }
+
+  public Level warning() {
+    return LevelImplRegular.WARNING;
+  }
+}
diff --git a/user/src/com/google/gwt/logging/impl/LoggerImpl.java b/user/src/com/google/gwt/logging/impl/LoggerImpl.java
new file mode 100644
index 0000000..edb15dd
--- /dev/null
+++ b/user/src/com/google/gwt/logging/impl/LoggerImpl.java
@@ -0,0 +1,59 @@
+/*
+ * 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.impl;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * Interface for the implementation of Logger. We use a LoggerImplNull to ensure
+ * that logging code compiles out when logging is disabled, and a
+ * LoggerImplRegular to provide normal functionality when logging is enabled.
+ */
+public interface LoggerImpl {
+  void addHandler(Handler handler);
+  void config(String msg);
+  void fine(String msg);
+  void finer(String msg);
+  void finest(String msg);
+  
+  /**
+   * Get the handlers attached to this logger.
+   * @return the array of handlers, or null if there are no handlers
+   */
+  Handler[] getHandlers();
+
+  Level getLevel();
+  Logger getLoggerHelper(String name);
+  String getName();
+  Logger getParent();
+  boolean getUseParentHandlers();
+  void info(String msg);
+  boolean isLoggable(Level messageLevel);
+  void log(Level level, String msg);
+  void log(Level level, String msg, Throwable thrown);
+  void log(LogRecord record);
+  void removeHandler(Handler handler);
+  void setLevel(Level newLevel);
+  void setName(String newName);
+  void setParent(Logger newParent);
+  void setUseParentHandlers(boolean newUseParentHandlers);
+  void severe(String msg);
+  void warning(String msg);
+}
diff --git a/user/src/com/google/gwt/logging/impl/LoggerImplNull.java b/user/src/com/google/gwt/logging/impl/LoggerImplNull.java
new file mode 100644
index 0000000..0f76c87
--- /dev/null
+++ b/user/src/com/google/gwt/logging/impl/LoggerImplNull.java
@@ -0,0 +1,126 @@
+/*
+ * 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.impl;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * Null implementation for the Logger class which ensures that calls to Logger
+ * compile out when logging is disabled.
+ */
+public class LoggerImplNull implements LoggerImpl {
+
+  public void addHandler(Handler handler) { 
+    // Do nothing
+  }
+
+  public void config(String msg) { 
+    // Do nothing
+  }
+
+  public void fine(String msg) { 
+    // Do nothing
+  }
+
+  public void finer(String msg) { 
+    // Do nothing
+  }
+
+  public void finest(String msg) { 
+    // Do nothing
+  }
+  
+  public Handler[] getHandlers() {
+    return null;
+  }
+
+  public Level getLevel() {
+    return null;
+  }
+  
+  public Logger getLoggerHelper(String name) {
+    // We need to return an actual logger here rather than null, because client
+    // code will make calls like Logger.getLogger().log(), and we don't want a
+    // NullPointerException. Since a LoggerImplNull will be behind this logger
+    // that we are returning, that will ensure that the log() call does nothing
+    // and gets compiled out.
+    return new LoggerWithExposedConstructor("");
+  }
+  
+  public String getName() {
+    return "";
+  }
+  
+  public Logger getParent() {
+    return null;
+  }
+  
+  public boolean getUseParentHandlers() {
+    return false;
+  }
+  
+  public void info(String msg) {
+    // Do nothing
+  }
+  
+  public boolean isLoggable(Level messageLevel) {
+    return false;
+  }
+  
+  public void log(Level level, String msg) {
+    // Do nothing  
+  }
+  
+  public void log(Level level, String msg, Throwable thrown) {
+    // Do nothing
+  }
+
+  public void log(LogRecord record) {
+    // Do nothing
+  }
+
+  public void removeHandler(Handler handler) { 
+    // Do nothing
+  }
+
+  public void setLevel(Level newLevel) { 
+    // Do nothing
+  }
+
+  public void setName(String newName) { 
+    // Do nothing
+  }
+
+  public void setParent(Logger newParent) { 
+    // Do nothing
+  }
+
+  public void setUseParentHandlers(boolean newUseParentHandlers) { 
+    // Do nothing
+  }
+
+  public void severe(String msg) { 
+    // Do nothing
+  }
+
+  public void warning(String msg) { 
+    // Do nothing
+  }  
+}
diff --git a/user/src/com/google/gwt/logging/impl/LoggerImplRegular.java b/user/src/com/google/gwt/logging/impl/LoggerImplRegular.java
new file mode 100644
index 0000000..73a4ba7
--- /dev/null
+++ b/user/src/com/google/gwt/logging/impl/LoggerImplRegular.java
@@ -0,0 +1,166 @@
+/*
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * Implementation for the Logger class when logging is enabled.
+ */
+public class LoggerImplRegular implements LoggerImpl {
+  private List<Handler> handlers;
+  private Level level = null;
+  private String name;
+  private Logger parent;  // Should never be null except in the RootLogger
+  private boolean useParentHandlers;
+  
+  public LoggerImplRegular() {
+    this.useParentHandlers = true;
+    handlers = new ArrayList<Handler>();
+  }
+  
+  public void addHandler(Handler handler) {
+    handlers.add(handler);
+  }
+  
+  public void config(String msg) {
+    log(Level.CONFIG, msg);
+  }
+  
+  public void fine(String msg) {
+    log(Level.FINE, msg);
+  }
+
+  public void finer(String msg) {
+    log(Level.FINER, msg);
+  } 
+   
+  public void finest(String msg) {
+    log(Level.FINEST, msg);
+  } 
+  
+  public Handler[] getHandlers() {
+    if (handlers.size() > 0) {
+      return (Handler[]) handlers.toArray();
+    }
+    return null;
+  }
+  
+  public Level getLevel() {
+    if (level != null) {
+      return level;
+    }
+    return getParent().getLevel();
+  }
+  
+  public Logger getLoggerHelper(String name) {
+    // Ideally, we'd just return LogManager.getLogManager.getOrAddLogger(name)
+    // here, since the code is basically the same, except that code gets to call
+    // addLoggerWithoutDuplicationChecking, which makes it somewhat more
+    // efficient. However, that means adding a public method to LogManager which
+    // is not in the API which is frowned upon.
+    LogManager manager = LogManager.getLogManager();
+    Logger logger = manager.getLogger(name);
+    if (logger == null) {
+      Logger newLogger = new LoggerWithExposedConstructor(name);
+      manager.addLogger(newLogger);
+      return newLogger;
+    }
+    return logger;
+  }
+  
+  public String getName() {
+    return name;
+  } 
+  
+  public Logger getParent() {
+    return parent;
+  }
+  
+  public boolean getUseParentHandlers() {
+    return useParentHandlers;
+  }
+  
+  public void info(String msg) {
+    log(Level.INFO, msg);
+  }
+  
+  public boolean isLoggable(Level messageLevel) {
+    return getLevel().intValue() <= messageLevel.intValue();
+  } 
+  
+  public void log(Level level, String msg) {
+    log(level, msg, null);
+  }
+  
+  public void log(Level level, String msg, Throwable thrown) {
+    if (isLoggable(level)) {
+      LogRecord record = new LogRecord(level, msg);
+      record.setThrown(thrown);
+      record.setLoggerName(getName());
+      log(record);
+    }
+  }
+  
+  public void log(LogRecord record) {
+    if (isLoggable(record.getLevel())) {
+      for (Handler h : handlers) {
+        h.publish(record);
+      }
+      if (useParentHandlers && parent != null) {
+        parent.log(record);
+      }
+    }
+  }
+
+  public void removeHandler(Handler handler) {
+    handlers.remove(handler);
+  }
+  
+  public void setLevel(Level newLevel) {
+    level = newLevel;
+  }
+  
+  public void setName(String newName) {
+    name = newName;
+  }
+  
+  public void setParent(Logger newParent) {
+    if (newParent != null) {
+      parent = newParent;
+    }
+  }
+  
+  public void setUseParentHandlers(boolean newUseParentHandlers) {
+    useParentHandlers = newUseParentHandlers;
+  }
+  
+  public void severe(String msg) {
+    log(Level.SEVERE, msg);
+  }
+  
+  public void warning(String msg) {
+    log(Level.WARNING, msg);
+  }
+
+}
diff --git a/user/src/com/google/gwt/logging/impl/LoggerWithExposedConstructor.java b/user/src/com/google/gwt/logging/impl/LoggerWithExposedConstructor.java
new file mode 100644
index 0000000..fe20f06
--- /dev/null
+++ b/user/src/com/google/gwt/logging/impl/LoggerWithExposedConstructor.java
@@ -0,0 +1,32 @@
+/*
+ * 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.impl;
+
+import java.util.logging.Logger;
+
+/**
+ * Since the Impl classes are in a different package than the classes they
+ * implement, they cannot use the protected Logger constructor. This subclass
+ * of Logger, which just explses the constructor, gets around that, and it's
+ * protected constructor is only available in the impl package, so clients
+ * cannot use it.
+ */
+public class LoggerWithExposedConstructor extends Logger {
+  protected LoggerWithExposedConstructor(String name) {
+    super(name, null);
+  }
+}
diff --git a/user/super/com/google/gwt/emul/Emulation.gwt.xml b/user/super/com/google/gwt/emul/Emulation.gwt.xml
index d74ae89..a6d85c2 100644
--- a/user/super/com/google/gwt/emul/Emulation.gwt.xml
+++ b/user/super/com/google/gwt/emul/Emulation.gwt.xml
@@ -15,6 +15,8 @@
 <!-- A JavaScript-based emulation of the Java Runtime library.              -->
 <!-- Do not inherit this module directly; inherit com.google.gwt.core.Core. -->
 <module>
+  <inherits name="com.google.gwt.logging.LogImpl"/>
+
   <replace-with class="com.google.gwt.core.client.impl.StringBufferImplArray">
     <when-type-is class="com.google.gwt.core.client.impl.StringBufferImpl"/>
   </replace-with>
diff --git a/user/super/com/google/gwt/emul/java/util/logging/Formatter.java b/user/super/com/google/gwt/emul/java/util/logging/Formatter.java
new file mode 100644
index 0000000..b0ce949
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/logging/Formatter.java
@@ -0,0 +1,35 @@
+/*
+ * 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 java.util.logging;
+
+/**
+ *  An emulation of the java.util.logging.Formatter class. See 
+ *  <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Formatter.html"> 
+ *  The Java API doc for details</a>
+ */
+public abstract class Formatter {
+  public abstract String format(LogRecord record);
+  
+  public String formatMessage(LogRecord record) {
+    return format(record);
+  }
+  
+  /* Not Implemented */
+  // public String getHead(Handler h) {} 
+  // public String getTail(Handler h) {}
+
+}
diff --git a/user/super/com/google/gwt/emul/java/util/logging/Handler.java b/user/super/com/google/gwt/emul/java/util/logging/Handler.java
new file mode 100644
index 0000000..3b89c3c
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/logging/Handler.java
@@ -0,0 +1,64 @@
+/*
+ * 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 java.util.logging;
+
+/**
+ *  An emulation of the java.util.logging.Handler class. See 
+ *  <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Handler.html"> 
+ *  The Java API doc for details</a>
+ */
+public abstract class Handler {
+  private Formatter formatter;
+  private Level level;
+  
+  public abstract void close(); 
+  public abstract void flush(); 
+  
+  public Formatter getFormatter() {
+    return formatter;
+  } 
+
+  public Level getLevel() {
+    if (level != null) {
+      return level;
+    }
+    return Level.ALL;
+  }  
+  
+  public boolean isLoggable(LogRecord record) {
+    return getLevel().intValue() <= record.getLevel().intValue();
+  } 
+  
+  public abstract void publish(LogRecord record); 
+  
+  public void setFormatter(Formatter newFormatter) {
+    formatter = newFormatter;
+  }  
+  
+  public void setLevel(Level newLevel) {
+    level = newLevel;
+  }
+  
+  /* Not Implemented */
+  // public String getEncoding() {} 
+  // public ErrorManager getErrorManager() {}  
+  // public Filter getFilter() {}
+  // public protected void reportError(String msg, Exception ex, int code) {}  
+  // public void setEncoding(String encoding) {} 
+  // public void setErrorManager(ErrorManager em) {}  
+  // public void setFilter(Filter newFilter) {} 
+}
diff --git a/user/super/com/google/gwt/emul/java/util/logging/Level.java b/user/super/com/google/gwt/emul/java/util/logging/Level.java
new file mode 100644
index 0000000..478bbbc
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/logging/Level.java
@@ -0,0 +1,71 @@
+/*
+ * 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 java.util.logging;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.logging.impl.LevelImpl;
+import com.google.gwt.logging.impl.LevelImplNull;
+
+import java.io.Serializable;
+
+/**
+ *  An emulation of the java.util.logging.Level class. See 
+ *  <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Level.html"> 
+ *  The Java API doc for details</a>
+ */
+public class Level implements Serializable {
+  private static LevelImpl staticImpl = GWT.create(LevelImplNull.class); 
+  public static Level ALL = staticImpl.all();
+  public static Level CONFIG = staticImpl.config(); 
+  public static Level FINE = staticImpl.fine(); 
+  public static Level FINER = staticImpl.finer(); 
+  public static Level FINEST = staticImpl.finest(); 
+  public static Level INFO = staticImpl.info(); 
+  public static Level OFF = staticImpl.off(); 
+  public static Level SEVERE = staticImpl.severe(); 
+  public static Level WARNING = staticImpl.warning();
+  
+  private LevelImpl impl;
+
+  protected Level(String name, int value) {
+    impl = GWT.create(LevelImplNull.class);
+    impl.setName(name);
+    impl.setValue(value);
+  }
+  
+  public String getName() {
+    return impl.getName();
+  }
+  
+  public int intValue() {
+    return impl.intValue();
+  }
+    
+  @Override
+  public String toString() {
+    return impl.toString();
+  }
+  
+  /* Not Implemented */
+  // public static Level parse(String name) {} 
+  // public boolean equals(Object ox) {} 
+  // protected Level(String name, int value, String resourceBundleName) {} 
+  // public String getLocalizedName() {}
+  // public String getResourceBundleName() {} 
+  // public int  hashCode() {}
+  
+}
diff --git a/user/super/com/google/gwt/emul/java/util/logging/LogManager.java b/user/super/com/google/gwt/emul/java/util/logging/LogManager.java
new file mode 100644
index 0000000..2dfec3f
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/logging/LogManager.java
@@ -0,0 +1,108 @@
+/*
+ * 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 java.util.logging;
+
+import java.util.HashMap;
+
+/**
+ *  An emulation of the java.util.logging.LogManager class. See 
+ *  <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/LogManger.html"> 
+ *  The Java API doc for details</a>
+ */
+public class LogManager {
+  /** 
+   * Since the Logger constructor is protected, the LogManager cannot create
+   * one directly, so we create a RootLogger which has an exposed constructor.
+   */
+  private class RootLogger extends Logger {
+    public RootLogger() {
+      super("", null);
+      setLevel(Level.ALL);
+    }
+  }
+
+  private static LogManager singleton;
+  
+  public static LogManager getLogManager() {
+    if (singleton == null) {
+      singleton = new LogManager();
+    }
+    return singleton;
+  }
+  
+  private HashMap<String, Logger> loggerList;
+  private Logger rootLogger;
+  
+  protected LogManager() {
+    loggerList = new HashMap<String, Logger>();
+    rootLogger = new RootLogger();
+    loggerList.put("", rootLogger);
+  }
+  
+  public boolean addLogger(Logger logger) {
+    if (getLogger(logger.getName()) != null) {
+      return false;
+    }
+    addLoggerWithoutDuplicationChecking(logger);
+    return true;
+  }
+
+  public Logger getLogger(String name) {
+    return loggerList.get(name);
+  }
+  
+  /**
+   *  Helper function to add a logger when we have already determined that it
+   *  does not exist.  When we add a logger, we recursively add all of it's
+   *  ancestors. Since loggers do not get removed, logger creation is cheap, 
+   *  and there are not usually too many loggers in an ancestry chain,
+   *  this is a simple way to ensure that the parent/child relationships are
+   *  always correctly set up.
+   */
+  private void addLoggerWithoutDuplicationChecking(Logger logger) {
+    String name = logger.getName();
+    String parentName = name.substring(0, Math.max(0, name.lastIndexOf('.')));
+    Logger parent = getOrAddLogger(parentName);
+    loggerList.put(logger.getName(), logger);
+    logger.setParent(parent);
+  }
+  
+  /**
+   *  Helper function to create a logger if it does not exist since the public
+   *  APIs for getLogger and addLogger make it difficult to use those functions
+   *  for this.
+   */ 
+  private Logger getOrAddLogger(String name) {
+    Logger logger = getLogger(name);
+    if (logger == null) {
+      Logger newLogger = new Logger(name, null);
+      addLoggerWithoutDuplicationChecking(newLogger);
+      return newLogger;
+    }
+    return logger;
+  }
+  
+  /* Not Implemented */
+  // public void addPropertyChangeListener(PropertyChangeListener l) {}
+  // public void checkAccess() {}
+  // public Enumeration getLoggerNames() {}
+  // public String getProperty(String name) {}
+  // public void readConfiguration() {}
+  // public void readConfiguration(InputStream ins) {}
+  // public void removePropertyChangeListener(PropertyChangeListener l) {} 
+  // public void reset() {}  
+}
diff --git a/user/super/com/google/gwt/emul/java/util/logging/LogRecord.java b/user/super/com/google/gwt/emul/java/util/logging/LogRecord.java
new file mode 100644
index 0000000..ef90fdc
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/logging/LogRecord.java
@@ -0,0 +1,99 @@
+/*
+ * 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 java.util.logging;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ *  An emulation of the java.util.logging.LogRecord class. See 
+ *  <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/LogRecord.html"> 
+ *  The Java API doc for details</a>
+ */
+public class LogRecord implements Serializable {
+  private Level level;
+  private String loggerName = "";
+  private String msg;
+  private Throwable thrown = null;
+  private Date timestamp;
+  
+  public LogRecord(Level level, String msg) {
+    this.level = level;
+    this.msg = msg;
+    timestamp = new Date();
+  }
+  
+  protected LogRecord() {
+    // for serialization
+  }
+  
+  public Level getLevel() {
+    return level;
+  }
+  
+  public String getLoggerName() {
+    return loggerName;
+  }
+  
+  public String getMessage() {
+    return msg;
+  }
+  
+  public long getMillis() {
+    return timestamp.getTime();
+  }
+  
+  public Throwable getThrown() {
+    return thrown;
+  } 
+  
+  public void setLevel(Level newLevel) {
+    level = newLevel;
+  } 
+  
+  public void setLoggerName(String newName) {
+    loggerName = newName;
+  }
+  
+  public void setMessage(String newMessage) {
+    msg = newMessage;
+  }
+  
+  public void setMillis(long millis) {
+    timestamp.setTime(millis);
+  }
+
+  public void setThrown(Throwable newThrown) {
+    thrown = newThrown;
+  }
+
+  /* Not Implemented */
+  // public Object[] getParameters() {} 
+  // public ResourceBundle getResourceBundle() {} 
+  // public String getResourceBundleName() {}
+  // public long getSequenceNumber() {}
+  // public String getSourceClassName() {}
+  // public String getSourceMethodName() {}
+  // public int getThreadID() {}
+  // public void setParameters(Object[] parameters) {} 
+  // public void setResourceBundle(ResourceBundle bundle) {} 
+  // public void setResourceBundleName(String name) {}
+  // public void setSequenceNumber(long seq) {}
+  // public void setSourceClassName(String sourceClassName) {} 
+  // public void setSourceMethodName(String sourceMethodName) {}
+  // public void setThreadID(int threadID) {}
+}
diff --git a/user/super/com/google/gwt/emul/java/util/logging/Logger.java b/user/super/com/google/gwt/emul/java/util/logging/Logger.java
new file mode 100644
index 0000000..55fdb79
--- /dev/null
+++ b/user/super/com/google/gwt/emul/java/util/logging/Logger.java
@@ -0,0 +1,149 @@
+/*
+ * 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 java.util.logging;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.logging.impl.LoggerImpl;
+import com.google.gwt.logging.impl.LoggerImplNull;
+
+/**
+ *  An emulation of the java.util.logging.Logger class. See 
+ *  <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/logging/Logger.html"> 
+ *  The Java API doc for details</a>
+ */
+public class Logger {
+  private static LoggerImpl staticImpl = GWT.create(LoggerImplNull.class);
+  
+  public static Logger getLogger(String name) {
+    return staticImpl.getLoggerHelper(name);
+  }
+
+  private LoggerImpl impl;
+  
+  protected Logger(String name, String resourceName) {
+    impl = GWT.create(LoggerImplNull.class);
+    impl.setName(name);
+  }
+
+  public void addHandler(Handler handler) {
+    impl.addHandler(handler);
+  }
+  
+  public void config(String msg) {
+    impl.config(msg);
+  } 
+   
+  public void fine(String msg) {
+    impl.fine(msg);
+  } 
+  
+  public void finer(String msg) {
+    impl.finer(msg);
+  }
+  
+  public void finest(String msg) {
+    impl.finest(msg);
+  }
+  
+  public Handler[] getHandlers() {
+    return impl.getHandlers();
+  }
+  
+  public Level getLevel() {
+    return impl.getLevel();
+  } 
+  
+  public String getName() {
+    return impl.getName();
+  }
+  
+  public Logger getParent() {
+    return impl.getParent();
+  }
+  
+  public boolean getUseParentHandlers() {
+    return impl.getUseParentHandlers();
+  }
+  
+  public void info(String msg) {
+    impl.info(msg);
+  } 
+  
+  public boolean isLoggable(Level messageLevel) {
+    return impl.isLoggable(messageLevel);
+  }
+  
+  public void log(Level level, String msg) {
+    impl.log(level, msg);
+  }
+  
+  public void log(Level level, String msg, Throwable thrown) {
+    impl.log(level, msg, thrown);
+  }
+
+  public void log(LogRecord record) {
+    impl.log(record);
+  }
+  
+  public void removeHandler(Handler handler) {
+    impl.removeHandler(handler);
+  }
+  
+  public void setLevel(Level newLevel) {
+    impl.setLevel(newLevel);
+  }
+  
+  public void setParent(Logger newParent) {
+    impl.setParent(newParent);
+  }
+  
+  public void setUseParentHandlers(boolean newUseParentHandlers) {
+    impl.setUseParentHandlers(newUseParentHandlers);
+  }
+  
+  public void severe(String msg) {
+    impl.severe(msg);
+  }
+  
+  public void warning(String msg) {
+    impl.warning(msg);
+  }
+ 
+  /* Not Implemented */
+  // public static Logger getAnonymousLogger() {
+  // public static Logger getAnonymousLogger(String resourceBundleName) {} 
+  // public Filter getFilter() {}
+  // public static Logger getLogger(String name, String resourceBundleName) {} 
+  // public ResourceBundle getResourceBundle() {} 
+  // public String getResourceBundleName() {}
+  // public void setFilter(Filter newFilter) {}
+  // public void entering(String sourceClass, String sourceMethod) {} 
+  // public void entering(String sourceClass, String sourceMethod, Object param1) {} 
+  // public void entering(String sourceClass, String sourceMethod, Object[] params) {}
+  // public void exiting(String sourceClass, String sourceMethod, Object result) {} 
+  // public void exiting(String sourceClass, String sourceMethod) {}
+  // public void log(Level level, String msg, Object param1) {} 
+  // public void log(Level level, String msg, Object[] params) {}
+  // public void logp(Level level, String sourceClass, String sourceMethod, String msg) {} 
+  // public void logp(Level level, String sourceClass, String sourceMethod, String msg, Object param1) {} 
+  // public void logp(Level level, String sourceClass, String sourceMethod, String msg, Object[] params) {}
+  // public void logp(Level level, String sourceClass, String sourceMethod, String msg, Throwable thrown) {}
+  // public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg) {}
+  // public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object param1) {} 
+  // public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object[] params) {}
+  // public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Throwable thrown) {}
+  // public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {} 
+}
\ No newline at end of file