001/*
002 * Copyright 2010-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2010-2018 Ping Identity Corporation
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 */
021package com.unboundid.util;
022
023
024
025import java.io.Serializable;
026import java.text.SimpleDateFormat;
027import java.util.Date;
028import java.util.logging.Formatter;
029import 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)
039public 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<>();
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 = new ThreadLocal<>();
065
066
067
068  /**
069   * The serial version UID for this serializable class.
070   */
071  private static final long serialVersionUID = -2884878613513769233L;
072
073
074
075  // Indicates whether to include the log level in the message header.
076  private final boolean includeLevel;
077
078  // Indicates whether to include a line break after the header.
079  private final boolean lineBreakAfterHeader;
080
081  // Indicates whether to include a line break after the message.
082  private final boolean lineBreakAfterMessage;
083
084  // The format string that will be used to generate timestamps, if appropriate.
085  private final String timestampFormat;
086
087
088
089  /**
090   * Creates a new instance of this log formatter with the default settings.
091   * Generated messages will include a timestamp generated using the format
092   * string "{@code '['dd/MMM/yyyy:HH:mm:ss Z']'}", will not include the log
093   * level, and will not include a line break after the timestamp or the
094   * message.
095   */
096  public MinimalLogFormatter()
097  {
098    this(DEFAULT_TIMESTAMP_FORMAT, false, false, false);
099  }
100
101
102
103  /**
104   * Creates a new instance of this log formatter with the provided
105   * configuration.
106   *
107   * @param  timestampFormat        The format string used to generate
108   *                                timestamps.  If this is {@code null}, then
109   *                                timestamps will not be included in log
110   *                                messages.
111   * @param  includeLevel           Indicates whether to include the log level
112   *                                in the generated messages.
113   * @param  lineBreakAfterHeader   Indicates whether to insert a line break
114   *                                after the timestamp and/or log level.
115   * @param  lineBreakAfterMessage  Indicates whether to insert aline break
116   *                                after the generated message.
117   */
118  public MinimalLogFormatter(final String timestampFormat,
119                             final boolean includeLevel,
120                             final boolean lineBreakAfterHeader,
121                             final boolean lineBreakAfterMessage)
122  {
123    this.timestampFormat       = timestampFormat;
124    this.includeLevel          = includeLevel;
125    this.lineBreakAfterHeader  = lineBreakAfterHeader;
126    this.lineBreakAfterMessage = lineBreakAfterMessage;
127  }
128
129
130
131  /**
132   * Formats the provided log record.
133   *
134   * @param  record  The log record to be formatted.
135   *
136   * @return  A string containing the formatted log record.
137   */
138  @Override()
139  public String format(final LogRecord record)
140  {
141    StringBuilder b = BUFFERS.get();
142    if (b == null)
143    {
144      b = new StringBuilder();
145      BUFFERS.set(b);
146    }
147    else
148    {
149      b.setLength(0);
150    }
151
152    if (timestampFormat != null)
153    {
154      SimpleDateFormat f = DATE_FORMATTERS.get();
155      if (f == null)
156      {
157        f = new SimpleDateFormat(timestampFormat);
158        DATE_FORMATTERS.set(f);
159      }
160
161      b.append(f.format(new Date()));
162    }
163
164    if (includeLevel)
165    {
166      if (b.length() > 0)
167      {
168        b.append(' ');
169      }
170
171      b.append(record.getLevel().toString());
172    }
173
174    if (lineBreakAfterHeader)
175    {
176      b.append(StaticUtils.EOL);
177    }
178    else if (b.length() > 0)
179    {
180      b.append(' ');
181    }
182
183    b.append(formatMessage(record));
184
185    if (lineBreakAfterMessage)
186    {
187      b.append(StaticUtils.EOL);
188    }
189
190    return b.toString();
191  }
192}