View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.util.internal.logging;
17  
18  import java.util.concurrent.atomic.AtomicReference;
19  
20  import static java.util.Objects.requireNonNull;
21  
22  /**
23   * Creates {@link InternalLogger}s. This factory allows you to choose what logging framework Netty should use. The
24   * default factory is {@link Slf4JLoggerFactory}. If SLF4J is not available, {@link Log4J2LoggerFactory} is used. If
25   * Log4J is not available, {@link JdkLoggerFactory} is used. You can change it to your preferred logging framework
26   * before other Netty classes are loaded via {@link #setDefaultFactory(InternalLoggerFactory)}. If you want to change
27   * the logger factory, {@link #setDefaultFactory(InternalLoggerFactory)} must be invoked before any other Netty classes
28   * are loaded.
29   * <strong>Note that {@link #setDefaultFactory(InternalLoggerFactory)}} can not be invoked more than once.</strong>
30   */
31  public abstract class InternalLoggerFactory {
32      /**
33       * This class holds a reference to the {@link InternalLoggerFactory}. The raison d'ĂȘtre for this class is primarily
34       * to aid in testing.
35       */
36      static final class InternalLoggerFactoryHolder {
37          static final InternalLoggerFactoryHolder HOLDER = new InternalLoggerFactoryHolder();
38  
39          private final AtomicReference<InternalLoggerFactory> reference;
40  
41          InternalLoggerFactoryHolder() {
42              reference = new AtomicReference<>();
43          }
44  
45          InternalLoggerFactoryHolder(final InternalLoggerFactory delegate) {
46              reference = new AtomicReference<>(delegate);
47          }
48  
49          InternalLoggerFactory getFactory() {
50              InternalLoggerFactory factory = reference.get();
51              if (factory == null) {
52                  factory = newDefaultFactory(InternalLoggerFactory.class.getName());
53                  if (!reference.compareAndSet(null, factory)) {
54                      factory = reference.get();
55                  }
56              }
57              return factory;
58          }
59  
60          void setFactory(final InternalLoggerFactory factory) {
61              requireNonNull(factory, "factory");
62              if (!reference.compareAndSet(null, factory)) {
63                  throw new IllegalStateException(
64                          "factory is already set to [" + reference + "], rejecting [" + factory + ']');
65              }
66          }
67  
68          InternalLogger getInstance(final Class<?> clazz) {
69              return getInstance(clazz.getName());
70          }
71  
72          InternalLogger getInstance(final String name) {
73              return newInstance(name);
74          }
75  
76          InternalLogger newInstance(String name) {
77              return getFactory().newInstance(name);
78          }
79  
80          private static InternalLoggerFactory newDefaultFactory(String name) {
81              InternalLoggerFactory f = useSlf4JLoggerFactory(name);
82              if (f != null) {
83                  return f;
84              }
85  
86              f = useLog4J2LoggerFactory(name);
87              if (f != null) {
88                  return f;
89              }
90  
91              return useJdkLoggerFactory(name);
92          }
93  
94          private static InternalLoggerFactory useSlf4JLoggerFactory(String name) {
95              try {
96                  InternalLoggerFactory f = Slf4JLoggerFactory.getInstanceWithNopCheck();
97                  f.newInstance(name).debug("Using SLF4J as the default logging framework");
98                  return f;
99              } catch (LinkageError | Exception ignore) {
100                 return null;
101             }
102         }
103 
104         private static InternalLoggerFactory useLog4J2LoggerFactory(String name) {
105             try {
106                 InternalLoggerFactory f = Log4J2LoggerFactory.INSTANCE;
107                 f.newInstance(name).debug("Using Log4J2 as the default logging framework");
108                 return f;
109             } catch (LinkageError | Exception ignore) {
110                 return null;
111             }
112         }
113 
114         private static InternalLoggerFactory useJdkLoggerFactory(String name) {
115             InternalLoggerFactory f = JdkLoggerFactory.INSTANCE;
116             f.newInstance(name).debug("Using java.util.logging as the default logging framework");
117             return f;
118         }
119     }
120 
121     /**
122      * Get the default factory that was either initialized automatically based on logging implementations on the
123      * classpath, or set explicitly via {@link #setDefaultFactory(InternalLoggerFactory)}.
124      */
125     public static InternalLoggerFactory getDefaultFactory() {
126         return InternalLoggerFactoryHolder.HOLDER.getFactory();
127     }
128 
129     /**
130      * Set the default factory. This method must be invoked before the default factory is initialized via
131      * {@link #getDefaultFactory()}, and can not be invoked multiple times.
132      *
133      * @param defaultFactory a non-null implementation of {@link InternalLoggerFactory}
134      */
135     public static void setDefaultFactory(InternalLoggerFactory defaultFactory) {
136         requireNonNull(defaultFactory, "defaultFactory");
137         InternalLoggerFactoryHolder.HOLDER.setFactory(defaultFactory);
138     }
139 
140     /**
141      * Creates a new logger instance with the name of the specified class.
142      */
143     public static InternalLogger getInstance(Class<?> clazz) {
144         return InternalLoggerFactoryHolder.HOLDER.getInstance(clazz);
145     }
146 
147     /**
148      * Creates a new logger instance with the specified name.
149      */
150     public static InternalLogger getInstance(String name) {
151         return InternalLoggerFactoryHolder.HOLDER.getInstance(name);
152     }
153 
154     /**
155      * Creates a new logger instance with the specified name.
156      */
157     protected abstract InternalLogger newInstance(String name);
158 }