001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.microservice;
014
015import static java.util.logging.Level.*;
016import java.util.logging.*;
017
018import org.apache.juneau.internal.*;
019import org.eclipse.jetty.util.log.AbstractLogger;
020
021/**
022 * Implementation of Jetty {@link Logger} based on {@link java.util.logging.Logger}.
023 *
024 * <p>
025 * Allows Jetty to log to the Java Util logging framework (and thus to the main log file defined in the
026 * <cc>[Logging]</cc> section).
027 *
028 * <p>
029 * Can be used by setting the following system property in the microservice config file.
030 *
031 * <p class='bcode w800'>
032 *    <cs>[SystemProperties]</cs>
033 *
034 *    <cc># Configure Jetty to log using java-util logging</cc>
035 *    <ck>org.eclipse.jetty.util.log.class</ck> = org.apache.juneau.microservice.JettyLogger
036 * </p>
037 *
038 */
039public class JettyLogger extends AbstractLogger {
040   private static final boolean SHOW_SOURCE = SystemUtils.getFirstBoolean(true, "org.eclipse.jetty.util.log.SOURCE", "org.eclipse.jetty.util.log.javautil.SOURCE");
041
042   private Level configuredLevel;
043   private Logger logger;
044
045   /**
046    * Default constructor.
047    *
048    * <p>
049    * Returns the logger with name <js>"org.eclipse.jetty.util.log.javautil"</js>.
050    */
051   public JettyLogger() {
052      this("org.eclipse.jetty.util.log.javautil");
053   }
054
055   /**
056    * Normal constructor.
057    *
058    * @param name The logger name.
059    */
060   public JettyLogger(String name) {
061      logger = Logger.getLogger(name);
062      configuredLevel = logger.getLevel();
063   }
064
065   @Override
066   public String getName() {
067      return logger.getName();
068   }
069
070   @Override
071   public void warn(String msg, Object... args) {
072      if (isLoggable(WARNING))
073         log(WARNING, format(msg, args), null);
074   }
075
076   @Override
077   public void warn(Throwable thrown) {
078      if (isLoggable(WARNING))
079         log(WARNING, "", thrown);
080   }
081
082   @Override
083   public void warn(String msg, Throwable thrown) {
084      if (isLoggable(WARNING))
085         log(WARNING, msg, thrown);
086   }
087
088   @Override
089   public void info(String msg, Object... args) {
090      if (isLoggable(INFO))
091         log(INFO, format(msg, args), null);
092   }
093
094   @Override
095   public void info(Throwable thrown) {
096      if (isLoggable(INFO))
097         log(INFO, "", thrown);
098   }
099
100   @Override
101   public void info(String msg, Throwable thrown) {
102      if (isLoggable(INFO))
103         log(INFO, msg, thrown);
104   }
105
106   @Override
107   public boolean isDebugEnabled() {
108      return isLoggable(FINE);
109   }
110
111   @Override
112   public void setDebugEnabled(boolean enabled) {
113      if (enabled) {
114         configuredLevel = logger.getLevel();
115         logger.setLevel(FINE);
116      } else {
117         logger.setLevel(configuredLevel);
118      }
119   }
120
121   @Override
122   public void debug(String msg, Object... args) {
123      if (isLoggable(FINE))
124         log(FINE, format(msg, args), null);
125   }
126
127   @Override
128   public void debug(String msg, long arg) {
129      if (isLoggable(FINE))
130         log(FINE, format(msg, arg), null);
131   }
132
133   @Override
134   public void debug(Throwable thrown) {
135      if (isLoggable(FINE))
136         log(FINE, "", thrown);
137   }
138
139   @Override
140   public void debug(String msg, Throwable thrown) {
141      if (isLoggable(FINE))
142         log(FINE, msg, thrown);
143   }
144
145   @Override
146   protected org.eclipse.jetty.util.log.Logger newLogger(String fullname) {
147      return new JettyLogger(fullname);
148   }
149
150   @Override
151   public void ignore(Throwable ignored) {
152      if (isLoggable(FINEST))
153         log(FINEST, org.eclipse.jetty.util.log.Log.IGNORED, ignored);
154   }
155
156   private static String format(String msg, Object... args) {
157      msg = String.valueOf(msg);
158      if (args.length == 0)
159         return msg;
160      StringBuilder sb = new StringBuilder();
161      int start = 0;
162      for (Object arg : args) {
163         int bi = msg.indexOf("{}", start);
164         if (bi < 0) {
165            sb.append(msg.substring(start)).append(" ").append(arg);
166            start = msg.length();
167         } else {
168            sb.append(msg.substring(start, bi)).append(String.valueOf(arg));
169            start = bi + 2;
170         }
171      }
172      sb.append(msg.substring(start));
173      return sb.toString();
174   }
175
176   private void log(Level level, String msg, Throwable thrown) {
177      LogRecord r = new LogRecord(level, msg);
178      if (thrown != null)
179         r.setThrown(thrown);
180      r.setLoggerName(logger.getName());
181      if (SHOW_SOURCE) {
182         StackTraceElement[] stack = new Throwable().getStackTrace();
183         for (int i = 0; i < stack.length; i++) {
184            StackTraceElement e = stack[i];
185            if (!e.getClassName().equals(getClass().getName())) {
186               r.setSourceClassName(e.getClassName());
187               r.setSourceMethodName(e.getMethodName());
188               break;
189            }
190         }
191      }
192      logger.log(r);
193   }
194
195   private boolean isLoggable(Level level) {
196      return logger.isLoggable(level);
197   }
198}