001    /*
002     * Copyright 2010-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2010-2015 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.util;
022    
023    
024    
025    import java.io.Serializable;
026    import java.text.SimpleDateFormat;
027    import java.util.Date;
028    import java.util.logging.Formatter;
029    import java.util.logging.LogRecord;
030    
031    
032    
033    /**
034     * This class provides a log formatter for use in the Java logging framework
035     * that may be used to minimize the formatting applied to log messages.
036     */
037    @NotMutable()
038    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
039    public final class MinimalLogFormatter
040           extends Formatter
041           implements Serializable
042    {
043      /**
044       * The default format string that will be used for generating timestamps.
045       */
046      public static final String DEFAULT_TIMESTAMP_FORMAT =
047           "'['dd/MMM/yyyy:HH:mm:ss Z']'";
048    
049    
050    
051      /**
052       * The set of thread-local date formatters that will be used for generating
053       * message timestamps.
054       */
055      private static final ThreadLocal<SimpleDateFormat> DATE_FORMATTERS =
056           new ThreadLocal<SimpleDateFormat>();
057    
058    
059    
060      /**
061       * The set of thread-local buffers that will be used for generating the
062       * message.
063       */
064      private static final ThreadLocal<StringBuilder> BUFFERS =
065           new ThreadLocal<StringBuilder>();
066    
067    
068    
069      /**
070       * The serial version UID for this serializable class.
071       */
072      private static final long serialVersionUID = -2884878613513769233L;
073    
074    
075    
076      // Indicates whether to include the log level in the message header.
077      private final boolean includeLevel;
078    
079      // Indicates whether to include a line break after the header.
080      private final boolean lineBreakAfterHeader;
081    
082      // Indicates whether to include a line break after the message.
083      private final boolean lineBreakAfterMessage;
084    
085      // The format string that will be used to generate timestamps, if appropriate.
086      private final String timestampFormat;
087    
088    
089    
090      /**
091       * Creates a new instance of this log formatter with the default settings.
092       * Generated messages will include a timestamp generated using the format
093       * string "{@code '['dd/MMM/yyyy:HH:mm:ss Z']'}", will not include the log
094       * level, and will not include a line break after the timestamp or the
095       * message.
096       */
097      public MinimalLogFormatter()
098      {
099        this(DEFAULT_TIMESTAMP_FORMAT, false, false, false);
100      }
101    
102    
103    
104      /**
105       * Creates a new instance of this log formatter with the provided
106       * configuration.
107       *
108       * @param  timestampFormat        The format string used to generate
109       *                                timestamps.  If this is {@code null}, then
110       *                                timestamps will not be included in log
111       *                                messages.
112       * @param  includeLevel           Indicates whether to include the log level
113       *                                in the generated messages.
114       * @param  lineBreakAfterHeader   Indicates whether to insert a line break
115       *                                after the timestamp and/or log level.
116       * @param  lineBreakAfterMessage  Indicates whether to insert aline break
117       *                                after the generated message.
118       */
119      public MinimalLogFormatter(final String timestampFormat,
120                                 final boolean includeLevel,
121                                 final boolean lineBreakAfterHeader,
122                                 final boolean lineBreakAfterMessage)
123      {
124        this.timestampFormat       = timestampFormat;
125        this.includeLevel          = includeLevel;
126        this.lineBreakAfterHeader  = lineBreakAfterHeader;
127        this.lineBreakAfterMessage = lineBreakAfterMessage;
128      }
129    
130    
131    
132      /**
133       * Formats the provided log record.
134       *
135       * @param  record  The log record to be formatted.
136       *
137       * @return  A string containing the formatted log record.
138       */
139      @Override()
140      public String format(final LogRecord record)
141      {
142        StringBuilder b = BUFFERS.get();
143        if (b == null)
144        {
145          b = new StringBuilder();
146          BUFFERS.set(b);
147        }
148        else
149        {
150          b.setLength(0);
151        }
152    
153        if (timestampFormat != null)
154        {
155          SimpleDateFormat f = DATE_FORMATTERS.get();
156          if (f == null)
157          {
158            f = new SimpleDateFormat(timestampFormat);
159            DATE_FORMATTERS.set(f);
160          }
161    
162          b.append(f.format(new Date()));
163        }
164    
165        if (includeLevel)
166        {
167          if (b.length() > 0)
168          {
169            b.append(' ');
170          }
171    
172          b.append(record.getLevel().toString());
173        }
174    
175        if (lineBreakAfterHeader)
176        {
177          b.append(StaticUtils.EOL);
178        }
179        else if (b.length() > 0)
180        {
181          b.append(' ');
182        }
183    
184        b.append(formatMessage(record));
185    
186        if (lineBreakAfterMessage)
187        {
188          b.append(StaticUtils.EOL);
189        }
190    
191        return b.toString();
192      }
193    }