package org.basex.server;
import static org.basex.util.Token.*;
import java.io.*;
import java.util.*;
import org.basex.core.*;
import org.basex.core.users.*;
import org.basex.io.*;
import org.basex.util.*;
/**
* This class writes daily log files to disk.
* The log format has been updated in Version 7.4; it now has the following columns:
* <ul>
* <li><b>Time</b>: timestamp (format: {@code xs:time})</li>
* <li><b>Address</b>: host name and port of the requesting client</li>
* <li><b>User</b>: user name</li>
* <li><b>Type</b>: Type of log message: REQUEST, OK or ERROR</li>
* <li><b>Info</b>: Log message</li>
* <li><b>Performance</b>: Measured time in milliseconds</li>
* </ul>
*
* @author BaseX Team 2005-17, BSD License
* @author Christian Gruen
*/
public final class Log {
/** Server string. */
public static final String SERVER = "SERVER";
/** Log types. */
public enum LogType {
/** Request. */ REQUEST,
/** Info. */ INFO,
/** Error. */ ERROR,
/** OK. */ OK
}
/** Static options. */
private final StaticOptions sopts;
/** Current log file. */
private LogFile file;
/**
* Constructor.
* @param sopts static options
*/
public Log(final StaticOptions sopts) {
this.sopts = sopts;
}
/**
* Returns a log file for the specified name (current or new instance).
* @param name name of log file
* @return log file, or {@code null} if it does not exist
*/
public LogFile file(final String name) {
LogFile lf = file;
if(lf == null || !lf.sameAs(name)) lf = new LogFile(name, dir());
return lf.exists() ? lf : null;
}
/**
* Writes a server entry to the log file.
* @param type log type
* @param info info string (can be {@code null})
*/
public void writeServer(final LogType type, final String info) {
write(SERVER, null, type, info, null);
}
/**
* Writes an entry to the log file.
* @param address address string
* @param user user ({@code admin} if null)
* @param type type (HTTP status code)
* @param info info string (can be {@code null})
* @param perf performance string
*/
public void write(final String address, final String user, final int type,
final String info, final Performance perf) {
write(address, user, Integer.toString(type), info, perf);
}
/**
* Writes an entry to the log file.
* @param address address string
* @param user user ({@code admin} if null)
* @param type type (ERROR, OK, REQUEST, INFO)
* @param info info string (can be {@code null})
* @param perf performance string
*/
public void write(final String address, final String user, final LogType type, final String info,
final Performance perf) {
write(address, user, type.toString(), info, perf);
}
/**
* Writes an entry to the log file.
* @param address address string
* @param user user ({@code admin} if null)
* @param type type (ERROR, OK, REQUEST, INFO, HTTP status code)
* @param info info string (can be {@code null})
* @param perf performance string
*/
public void write(final String address, final String user, final String type, final String info,
final Performance perf) {
// check if logging is disabled
if(!sopts.get(StaticOptions.LOG)) return;
// construct log text
final Date date = new Date();
final int ml = sopts.get(StaticOptions.LOGMSGMAXLEN);
final TokenBuilder tb = new TokenBuilder();
tb.add(DateTime.format(date, DateTime.TIME));
tb.add('\t').add(address);
tb.add('\t').add(user == null ? UserText.ADMIN : user);
tb.add('\t').add(type);
tb.add('\t').add(info == null ? EMPTY : chop(normalize(token(info)), ml));
if(perf != null) tb.add('\t').add(perf.toString());
tb.add(Prop.NL);
try {
synchronized(sopts) {
// create new log file and write log entry
final String name = DateTime.format(date, DateTime.DATE);
if(file != null && !file.sameAs(name)) close();
if(file == null) file = LogFile.create(name, dir());
// write log entry
file.write(tb.finish());
}
} catch(final IOException ex) {
Util.stack(ex);
}
}
/**
* Closes the log file.
*/
public void close() {
try {
synchronized(sopts) {
if(file != null) {
file.close();
file = null;
}
}
} catch(final IOException ex) {
Util.stack(ex);
}
}
/**
* Returns all log files.
* @return log directory
*/
public IOFile[] files() {
return dir().children(".*\\" + IO.LOGSUFFIX);
}
/**
* Returns a reference to the log directory.
* @return log directory
*/
private IOFile dir() {
return sopts.dbPath(".").resolve(sopts.get(StaticOptions.LOGPATH));
}
}