Преглед изворни кода

Merge pull request #578 from greboid/dev2

Initial work on logback logging.
pull/579/head
Chris Smith пре 9 година
родитељ
комит
cf32dcae39
4 измењених фајлова са 254 додато и 2 уклоњено
  1. 1
    0
      build.gradle
  2. 31
    2
      src/com/dmdirc/Main.java
  3. 80
    0
      src/com/dmdirc/ProgramErrorAppender.java
  4. 142
    0
      src/com/dmdirc/util/LogUtils.java

+ 1
- 0
build.gradle Прегледај датотеку

@@ -36,6 +36,7 @@ dependencies {
36 36
     compile group: 'com.squareup.dagger', name: 'dagger-compiler', version: '1.2.1'
37 37
     compile group: 'com.google.auto.value', name: 'auto-value', version: '1.0'
38 38
 
39
+    bundle group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2'
39 40
     bundle group: 'org.slf4j', name: 'slf4j-api', version:'1.7.10'
40 41
     bundle group: 'com.squareup.dagger', name: 'dagger', version: '1.2.1'
41 42
     bundle group: 'com.esotericsoftware.yamlbeans', name: 'yamlbeans', version: '1.08'

+ 31
- 2
src/com/dmdirc/Main.java Прегледај датотеку

@@ -43,6 +43,10 @@ import com.dmdirc.plugins.ServiceManager;
43 43
 import com.dmdirc.plugins.ServiceProvider;
44 44
 import com.dmdirc.ui.WarningDialog;
45 45
 
46
+import ch.qos.logback.classic.LoggerContext;
47
+import ch.qos.logback.classic.joran.JoranConfigurator;
48
+import ch.qos.logback.core.spi.ContextAware;
49
+
46 50
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
47 51
 
48 52
 import java.awt.GraphicsEnvironment;
@@ -55,6 +59,9 @@ import java.util.concurrent.TimeUnit;
55 59
 
56 60
 import javax.inject.Inject;
57 61
 
62
+import org.slf4j.Logger;
63
+import org.slf4j.LoggerFactory;
64
+
58 65
 import dagger.ObjectGraph;
59 66
 
60 67
 /**
@@ -62,6 +69,7 @@ import dagger.ObjectGraph;
62 69
  */
63 70
 public class Main {
64 71
 
72
+    private final Logger log = LoggerFactory.getLogger(Main.class);
65 73
     /** The UI to use for the client. */
66 74
     private final Collection<UIController> CONTROLLERS = new HashSet<>();
67 75
     /** The identity manager the client will use. */
@@ -90,6 +98,14 @@ public class Main {
90 98
     private final ModeAliasReporter reporter;
91 99
     private final ServiceManager serviceManager;
92 100
 
101
+    static {
102
+        // TODO: Can this go in a Dagger module?
103
+        final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
104
+        final ContextAware configurator = new JoranConfigurator();
105
+        configurator.setContext(context);
106
+        context.reset();
107
+    }
108
+
93 109
     /**
94 110
      * Creates a new instance of {@link Main}.
95 111
      */
@@ -160,6 +176,7 @@ public class Main {
160 176
      */
161 177
     public void init() {
162 178
         Thread.setDefaultUncaughtExceptionHandler(new DMDircExceptionHandler(eventBus));
179
+        setupLogback();
163 180
         migrators.stream().filter(Migrator::needsMigration).forEach(Migrator::migrate);
164 181
         commands.forEach(c -> commandManager.registerCommand(c.getCommand(), c.getInfo()));
165 182
 
@@ -250,10 +267,22 @@ public class Main {
250 267
             identityManager.getUserSettings().setOption("general", "firstRun", "false");
251 268
             eventBus.publish(new FirstRunEvent());
252 269
 
253
-            Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder()
254
-                    .setNameFormat("feedback-nag-%d").build()).schedule(
270
+            Executors.newSingleThreadScheduledExecutor(
271
+                    new ThreadFactoryBuilder().setNameFormat("feedback-nag-%d").build()).schedule(
255 272
                     () -> eventBus.publishAsync(new FeedbackNagEvent()), 5, TimeUnit.MINUTES);
256 273
         }
257 274
     }
258 275
 
276
+    private void setupLogback() {
277
+        // TODO: Add a normal logging thing, with or without runtime switching.
278
+        final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
279
+        final ProgramErrorAppender appender = new ProgramErrorAppender();
280
+        appender.setEventBus(eventBus);
281
+        appender.setContext(context);
282
+        appender.setName("Error Logger");
283
+        appender.start();
284
+        final ch.qos.logback.classic.Logger rootLogger = context.getLogger(Logger.ROOT_LOGGER_NAME);
285
+        rootLogger.addAppender(appender);
286
+    }
287
+
259 288
 }

+ 80
- 0
src/com/dmdirc/ProgramErrorAppender.java Прегледај датотеку

@@ -0,0 +1,80 @@
1
+/*
2
+ * Copyright (c) 2006-2015 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc;
24
+
25
+import com.dmdirc.events.AppErrorEvent;
26
+import com.dmdirc.events.UserErrorEvent;
27
+import com.dmdirc.logger.ErrorLevel;
28
+import com.dmdirc.logger.ProgramError;
29
+
30
+import ch.qos.logback.classic.spi.ILoggingEvent;
31
+import ch.qos.logback.core.AppenderBase;
32
+
33
+import static com.dmdirc.util.LogUtils.APP_ERROR;
34
+import static com.dmdirc.util.LogUtils.FATAL_APP_ERROR;
35
+import static com.dmdirc.util.LogUtils.FATAL_USER_ERROR;
36
+import static com.dmdirc.util.LogUtils.USER_ERROR;
37
+import static com.dmdirc.util.LogUtils.getErrorLevel;
38
+import static com.dmdirc.util.LogUtils.getThrowable;
39
+
40
+/**
41
+ * Converts log states into {@link ProgramError}s so they can be displayed to the user.
42
+ */
43
+public class ProgramErrorAppender extends AppenderBase<ILoggingEvent> {
44
+
45
+    private DMDircMBassador eventBus;
46
+
47
+    @Override
48
+    public void start() {
49
+        if (eventBus == null) {
50
+            addError("No eventBus set for the appender named ["+ name +"].");
51
+            return;
52
+        }
53
+        super.start();
54
+    }
55
+
56
+    @Override
57
+    protected void append(final ILoggingEvent eventObject) {
58
+        if (eventObject.getMarker() == null) {
59
+            return;
60
+        }
61
+        if (eventObject.getMarker() == APP_ERROR) {
62
+            eventBus.publish(new AppErrorEvent(
63
+                    getErrorLevel(eventObject.getLevel()),
64
+                    getThrowable(eventObject), eventObject.getFormattedMessage(), ""));
65
+        } else if (eventObject.getMarker() == USER_ERROR) {
66
+            eventBus.publish(new UserErrorEvent(getErrorLevel(eventObject.getLevel()),
67
+                    getThrowable(eventObject), eventObject.getFormattedMessage(), ""));
68
+        } else if (eventObject.getMarker() == FATAL_APP_ERROR) {
69
+            eventBus.publish(new AppErrorEvent(ErrorLevel.FATAL, getThrowable(eventObject),
70
+                    eventObject.getFormattedMessage(), ""));
71
+        } else if (eventObject.getMarker() == FATAL_USER_ERROR) {
72
+            eventBus.publish(new UserErrorEvent(ErrorLevel.FATAL, getThrowable(eventObject),
73
+                    eventObject.getFormattedMessage(), ""));
74
+        }
75
+    }
76
+
77
+    public void setEventBus(final DMDircMBassador eventBus) {
78
+        this.eventBus = eventBus;
79
+    }
80
+}

+ 142
- 0
src/com/dmdirc/util/LogUtils.java Прегледај датотеку

@@ -0,0 +1,142 @@
1
+/*
2
+ * Copyright (c) 2006-2015 DMDirc Developers
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ * SOFTWARE.
21
+ */
22
+
23
+package com.dmdirc.util;
24
+
25
+import com.dmdirc.logger.ErrorLevel;
26
+
27
+import ch.qos.logback.classic.Level;
28
+import ch.qos.logback.classic.spi.ILoggingEvent;
29
+import ch.qos.logback.classic.spi.IThrowableProxy;
30
+import ch.qos.logback.classic.spi.StackTraceElementProxy;
31
+
32
+import java.lang.reflect.Constructor;
33
+
34
+import javax.annotation.Nonnull;
35
+import javax.annotation.Nullable;
36
+
37
+import org.slf4j.Marker;
38
+import org.slf4j.MarkerFactory;
39
+
40
+/**
41
+ * Utility methods for logging in the client.
42
+ */
43
+public final class LogUtils {
44
+
45
+    public static final Marker USER_ERROR = MarkerFactory.getMarker("UserError");
46
+    public static final Marker APP_ERROR = MarkerFactory.getMarker("AppError");
47
+    public static final Marker FATAL_USER_ERROR = MarkerFactory.getMarker("FatalUserError");
48
+    public static final Marker FATAL_APP_ERROR = MarkerFactory.getMarker("FatalAppError");
49
+
50
+    private LogUtils() {
51
+    }
52
+
53
+    /**
54
+     * Converts a SLF4J {@link Level} into a DMDirc {@link ErrorLevel}
55
+     *
56
+     * @param level Error to convert
57
+     *
58
+     * @return Converted error
59
+     */
60
+    @Nonnull
61
+    public static ErrorLevel getErrorLevel(@Nonnull final Level level) {
62
+        if (level.equals(Level.ERROR)) {
63
+            return ErrorLevel.HIGH;
64
+        } else if (level.equals(Level.WARN)) {
65
+            return ErrorLevel.MEDIUM;
66
+        } else if (level.equals(Level.INFO)) {
67
+            return ErrorLevel.LOW;
68
+        } else {
69
+            return ErrorLevel.UNKNOWN;
70
+        }
71
+    }
72
+
73
+    /**
74
+     * Converts the {@link IThrowableProxy} from an SLF4J {@link ILoggingEvent} into a
75
+     * {@link Throwable}.
76
+     *
77
+     * @param eventObject Event containing the {@link IThrowableProxy}
78
+     *
79
+     * @return {@link Throwable} representation of the {@link IThrowableProxy} or {@code null} if
80
+     *         there is no {@link IThrowableProxy} present.
81
+     */
82
+    @Nullable
83
+    public static Throwable getThrowable(final ILoggingEvent eventObject) {
84
+        if (eventObject.getThrowableProxy() == null) {
85
+            return null;
86
+        }
87
+        try {
88
+            return getThrowable(eventObject.getThrowableProxy());
89
+        } catch (ReflectiveOperationException ex) {
90
+            return new IllegalStateException("Error converting exception");
91
+        }
92
+    }
93
+
94
+    /**
95
+     * Converts a SLF4J {@link IThrowableProxy} into a {@link Throwable}.
96
+     *
97
+     * @param proxy {@link IThrowableProxy} to convert
98
+     *
99
+     * @return {@link Throwable} representation of the {@link IThrowableProxy}
100
+     *
101
+     * @throws ReflectiveOperationException If an error ocurred creating the real {@link Throwable}
102
+     */
103
+    @Nonnull
104
+    public static Throwable getThrowable(@Nonnull final IThrowableProxy proxy)
105
+            throws ReflectiveOperationException {
106
+        final Class<Throwable> clazz = getThrowableClass(proxy.getClassName());
107
+        final Throwable throwable;
108
+        if (proxy.getCause() == null) {
109
+            final Constructor<Throwable> ctor = clazz.getDeclaredConstructor(String.class);
110
+            throwable = ctor.newInstance(proxy.getMessage());
111
+        } else {
112
+            final Constructor<Throwable> ctor = clazz.getDeclaredConstructor(String.class,
113
+                    Throwable.class);
114
+            throwable = ctor.newInstance(proxy.getMessage(), getThrowable(proxy.getCause()));
115
+        }
116
+        throwable.setStackTrace(getStackTraceElements(proxy.getStackTraceElementProxyArray()));
117
+        return throwable;
118
+    }
119
+
120
+    /**
121
+     * Converts an SLF4F {@link StackTraceElementProxy}[] into a {@link StackTraceElement}[].
122
+     *
123
+     * @param elements {@link StackTraceElementProxy}s to convert
124
+     *
125
+     * @return Non null {@link StackTraceElement}[] of the input
126
+     */
127
+    @Nonnull
128
+    public static StackTraceElement[] getStackTraceElements(
129
+            final StackTraceElementProxy... elements) {
130
+        final StackTraceElement[] returnValue = new StackTraceElement[elements.length];
131
+        for (int i = 0; i < elements.length; i++) {
132
+            returnValue[i] = elements[i].getStackTraceElement();
133
+        }
134
+        return returnValue;
135
+    }
136
+
137
+    @SuppressWarnings("unchecked")
138
+    private static Class<Throwable> getThrowableClass(final String string)
139
+            throws ClassNotFoundException {
140
+        return (Class<Throwable>) Class.forName(string);
141
+    }
142
+}

Loading…
Откажи
Сачувај