Adds SQL logging from WhiteX's fork; closes #869

This commit is contained in:
Lucas Nicodemus 2015-02-25 14:52:28 -07:00
parent c215ff8e10
commit 0459dfca11
10 changed files with 743 additions and 144 deletions

View file

@ -67,7 +67,7 @@ namespace TShockAPI
SaveManager.Instance.SaveWorld();
Console.WriteLine("World backed up.");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Info(string.Format("World backed up ({0}).", Main.worldPathName));
TShock.Log.Info(string.Format("World backed up ({0}).", Main.worldPathName));
Main.worldPathName = worldname;
}
@ -76,8 +76,8 @@ namespace TShockAPI
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Backup failed!");
Console.ForegroundColor = ConsoleColor.Gray;
Log.Error("Backup failed!");
Log.Error(ex.ToString());
TShock.Log.Error("Backup failed!");
TShock.Log.Error(ex.ToString());
}
}

View file

@ -151,7 +151,7 @@ namespace TShockAPI
catch (Exception e)
{
ply.SendErrorMessage("Command failed, check logs for more details.");
Log.Error(e.ToString());
TShock.Log.Error(e.ToString());
}
return true;
@ -711,7 +711,7 @@ namespace TShockAPI
{
if (args.Player.LoginAttempts > TShock.Config.MaximumLoginAttempts && (TShock.Config.MaximumLoginAttempts != -1))
{
Log.Warn(String.Format("{0} ({1}) had {2} or more invalid login attempts and was kicked automatically.",
TShock.Log.Warn(String.Format("{0} ({1}) had {2} or more invalid login attempts and was kicked automatically.",
args.Player.IP, args.Player.Name, TShock.Config.MaximumLoginAttempts));
TShock.Utils.Kick(args.Player, "Too many invalid login attempts.");
return;
@ -799,7 +799,7 @@ namespace TShockAPI
}
args.Player.SendSuccessMessage("Authenticated as " + user.Name + " successfully.");
Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user: " + user.Name + ".");
TShock.Log.ConsoleInfo(args.Player.Name + " authenticated successfully as user: " + user.Name + ".");
if ((args.Player.LoginHarassed) && (TShock.Config.RememberLeavePos))
{
if (TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP) != Vector2.Zero)
@ -824,14 +824,14 @@ namespace TShockAPI
{
args.Player.SendErrorMessage("Invalid password!");
}
Log.Warn(args.Player.IP + " failed to authenticate as user: " + user.Name + ".");
TShock.Log.Warn(args.Player.IP + " failed to authenticate as user: " + user.Name + ".");
args.Player.LoginAttempts++;
}
}
catch (Exception ex)
{
args.Player.SendErrorMessage("There was an error processing your request.");
Log.Error(ex.ToString());
TShock.Log.Error(ex.ToString());
}
}
@ -847,12 +847,12 @@ namespace TShockAPI
{
args.Player.SendSuccessMessage("You changed your password!");
TShock.Users.SetUserPassword(user, args.Parameters[1]); // SetUserPassword will hash it for you.
Log.ConsoleInfo(args.Player.IP + " named " + args.Player.Name + " changed the password of account " + user.Name + ".");
TShock.Log.ConsoleInfo(args.Player.IP + " named " + args.Player.Name + " changed the password of account " + user.Name + ".");
}
else
{
args.Player.SendErrorMessage("You failed to change your password!");
Log.ConsoleError(args.Player.IP + " named " + args.Player.Name + " failed to change password for account: " +
TShock.Log.ConsoleError(args.Player.IP + " named " + args.Player.Name + " failed to change password for account: " +
user.Name + ".");
}
}
@ -864,7 +864,7 @@ namespace TShockAPI
catch (UserManagerException ex)
{
args.Player.SendErrorMessage("Sorry, an error occured: " + ex.Message + ".");
Log.ConsoleError("PasswordUser returned an error: " + ex);
TShock.Log.ConsoleError("PasswordUser returned an error: " + ex);
}
}
@ -898,18 +898,18 @@ namespace TShockAPI
args.Player.SendSuccessMessage("Account \"{0}\" has been registered.", user.Name);
args.Player.SendSuccessMessage("Your password is {0}.", user.Password);
TShock.Users.AddUser(user);
Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, user.Name);
TShock.Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, user.Name);
}
else
{
args.Player.SendErrorMessage("Account " + user.Name + " has already been registered.");
Log.ConsoleInfo(args.Player.Name + " failed to register an existing account: " + user.Name);
TShock.Log.ConsoleInfo(args.Player.Name + " failed to register an existing account: " + user.Name);
}
}
catch (UserManagerException ex)
{
args.Player.SendErrorMessage("Sorry, an error occured: " + ex.Message + ".");
Log.ConsoleError("RegisterUser returned an error: " + ex);
TShock.Log.ConsoleError("RegisterUser returned an error: " + ex);
}
}
@ -939,7 +939,7 @@ namespace TShockAPI
{
TShock.Users.AddUser(user);
args.Player.SendSuccessMessage("Account " + user.Name + " has been added to group " + user.Group + "!");
Log.ConsoleInfo(args.Player.Name + " added Account " + user.Name + " to group " + user.Group);
TShock.Log.ConsoleInfo(args.Player.Name + " added Account " + user.Name + " to group " + user.Group);
}
catch (GroupNotExistsException e)
{
@ -952,7 +952,7 @@ namespace TShockAPI
catch (UserManagerException e)
{
args.Player.SendErrorMessage("User " + user.Name + " could not be added, check console for details.");
Log.ConsoleError(e.ToString());
TShock.Log.ConsoleError(e.ToString());
}
}
else
@ -970,7 +970,7 @@ namespace TShockAPI
{
TShock.Users.RemoveUser(user);
args.Player.SendSuccessMessage("Account removed successfully.");
Log.ConsoleInfo(args.Player.Name + " successfully deleted account: " + args.Parameters[1] + ".");
TShock.Log.ConsoleInfo(args.Player.Name + " successfully deleted account: " + args.Parameters[1] + ".");
}
catch (UserNotExistException e)
{
@ -979,7 +979,7 @@ namespace TShockAPI
catch (UserManagerException ex)
{
args.Player.SendMessage(ex.Message, Color.Red);
Log.ConsoleError(ex.ToString());
TShock.Log.ConsoleError(ex.ToString());
}
}
@ -994,7 +994,7 @@ namespace TShockAPI
try
{
TShock.Users.SetUserPassword(user, args.Parameters[2]);
Log.ConsoleInfo(args.Player.Name + " changed the password of account " + user.Name);
TShock.Log.ConsoleInfo(args.Player.Name + " changed the password of account " + user.Name);
args.Player.SendSuccessMessage("Password change succeeded for " + user.Name + ".");
}
catch (UserNotExistException e)
@ -1004,7 +1004,7 @@ namespace TShockAPI
catch (UserManagerException e)
{
args.Player.SendErrorMessage("Password change for " + user.Name + " failed! Check console!");
Log.ConsoleError(e.ToString());
TShock.Log.ConsoleError(e.ToString());
}
}
else
@ -1023,7 +1023,7 @@ namespace TShockAPI
try
{
TShock.Users.SetUserGroup(user, args.Parameters[2]);
Log.ConsoleInfo(args.Player.Name + " changed account " + user.Name + " to group " + args.Parameters[2] + ".");
TShock.Log.ConsoleInfo(args.Player.Name + " changed account " + user.Name + " to group " + args.Parameters[2] + ".");
args.Player.SendSuccessMessage("Account " + user.Name + " has been changed to group " + args.Parameters[2] + "!");
}
catch (GroupNotExistsException e)
@ -1626,7 +1626,7 @@ namespace TShockAPI
{
if (ServerApi.RunningMono)
{
Log.ConsoleInfo("Sorry, this command has not yet been implemented in Mono.");
TShock.Log.ConsoleInfo("Sorry, this command has not yet been implemented in Mono.");
}
else
{
@ -3688,7 +3688,7 @@ namespace TShockAPI
}
plr.DamagePlayer(damage);
TSPlayer.All.SendInfoMessage("{0} slapped {1} for {2} damage.", args.Player.Name, plr.Name, damage);
Log.Info("{0} slapped {1} for {2} damage.", args.Player.Name, plr.Name, damage);
TShock.Log.Info("{0} slapped {1} for {2} damage.", args.Player.Name, plr.Name, damage);
}
}
@ -4381,7 +4381,7 @@ namespace TShockAPI
if (TShock.AuthToken == 0)
{
args.Player.SendWarningMessage("Auth is disabled. This incident has been logged.");
Log.Warn(args.Player.IP + " attempted to use /auth even though it's disabled.");
TShock.Log.Warn(args.Player.IP + " attempted to use /auth even though it's disabled.");
return;
}
int givenCode = Convert.ToInt32(args.Parameters[0]);
@ -4398,7 +4398,7 @@ namespace TShockAPI
}
catch (UserManagerException ex)
{
Log.ConsoleError(ex.ToString());
TShock.Log.ConsoleError(ex.ToString());
args.Player.SendErrorMessage(ex.Message);
}
return;
@ -4414,7 +4414,7 @@ namespace TShockAPI
}
args.Player.SendErrorMessage("Incorrect auth code. This incident has been logged.");
Log.Warn(args.Player.IP + " attempted to use an incorrect auth code.");
TShock.Log.Warn(args.Player.IP + " attempted to use an incorrect auth code.");
}
private static void AuthVerify(CommandArgs args)

View file

@ -325,6 +325,12 @@ namespace TShockAPI
[Description("The path of the directory where logs should be written into.")]
public string LogPath = "tshock";
[Description("Save logs to an SQL database instead of a text file. Default = false")]
public bool UseSqlLogs = false;
[Description("Number of times the SQL log must fail to insert logs before falling back to the text log")]
public int RevertToTextLogsOnSqlFailures = 10;
[Description("Prevents players from placing tiles with an invalid style.")]
public bool PreventInvalidPlaceStyle = true;

140
TShockAPI/ILog.cs Normal file
View file

@ -0,0 +1,140 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
namespace TShockAPI
{
[Flags]
public enum LogLevel
{
None = 0,
Debug = 1,
Info = 2,
Warning = 4,
Error = 8,
Data = 16,
All = 31
}
/// <summary>
/// Logging interface
/// </summary>
public interface ILog
{
/// <summary>
/// Log name
/// </summary>
string Name { get; }
/// <summary>
/// Returns true if the ILog is using SQL or false if not
/// </summary>
bool Sql { get; }
/// <summary>
/// Checks whether the log level contains the specified flag.
/// </summary>
/// <param name="type">The <see cref="LogLevel" /> value to check.</param>
bool MayWriteType(LogLevel type);
/// <summary>
/// Writes an informative string to the log and to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
void ConsoleInfo(string message);
/// <summary>
/// Writes an informative string to the log and to the console.
/// </summary>
/// <param name="message">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void ConsoleInfo(string format, params object[] args);
/// <summary>
/// Writes an error message to the log and to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
void ConsoleError(string message);
/// <summary>
/// Writes an error message to the log and to the console.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void ConsoleError(string format, params object[] args);
/// <summary>
/// Writes a warning to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Warn(string message);
/// <summary>
/// Writes a warning to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Warn(string format, params object[] args);
/// <summary>
/// Writes an error to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Error(string message);
/// <summary>
/// Writes an error to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Error(string format, params object[] args);
/// <summary>
/// Writes an informative string to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Info(string message);
/// <summary>
/// Writes an informative string to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Info(string format, params object[] args);
/// <summary>
/// Writes data to the log.
/// </summary>
/// <param name="message">The message to be written.</param>
void Data(string message);
/// <summary>
/// Writes data to the log.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
void Data(string format, params object[] args);
/// <summary>
/// Writes a message to the log
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="level">LogLevel assosciated with the message</param>
void Write(string message, LogLevel level);
/// <summary>
/// Dispose the Log
/// </summary>
void Dispose();
}
}

View file

@ -17,57 +17,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
namespace TShockAPI
{
[Flags]
public enum LogLevel
{
None = 0,
Debug = 1,
Info = 2,
Warning = 4,
Error = 8,
Data = 16,
All = 31
}
public static class Log
{
public static string _filename { get; private set; }
private static LogLevel _logLevel;
private static StreamWriter _logWriter;
/// <summary>
/// Creates the log file stream and sets the initial log level.
/// </summary>
/// <param name="filename">The output filename. This file will be overwritten if 'clear' is set.</param>
/// <param name="logLevel">The <see cref="LogLevel" /> value which sets the type of messages to output.</param>
/// <param name="clear">Whether or not to clear the log file on initialization.</param>
public static void Initialize(string filename, LogLevel logLevel, bool clear)
{
_filename = filename;
_logLevel = logLevel;
_logWriter = new StreamWriter(filename, !clear);
}
/// <summary>
/// Checks whether the log level contains the specified flag.
/// </summary>
/// <param name="type">The <see cref="LogLevel" /> value to check.</param>
private static bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Data")]
public static void Data(String message)
{
Write(message, LogLevel.Data);
@ -78,6 +37,7 @@ namespace TShockAPI
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Data")]
public static void Data(string format, params object[] args)
{
Data(String.Format(format, args));
@ -87,6 +47,7 @@ namespace TShockAPI
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Error")]
public static void Error(String message)
{
Write(message, LogLevel.Error);
@ -97,6 +58,7 @@ namespace TShockAPI
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Error")]
public static void Error(string format, params object[] args)
{
Error(String.Format(format, args));
@ -106,6 +68,7 @@ namespace TShockAPI
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.ConsoleError")]
public static void ConsoleError(String message)
{
Console.ForegroundColor = ConsoleColor.Red;
@ -119,6 +82,7 @@ namespace TShockAPI
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.ConsoleError")]
public static void ConsoleError(string format, params object[] args)
{
ConsoleError(String.Format(format, args));
@ -128,6 +92,7 @@ namespace TShockAPI
/// Writes a warning to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Warn")]
public static void Warn(String message)
{
Write(message, LogLevel.Warning);
@ -138,6 +103,7 @@ namespace TShockAPI
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Warn")]
public static void Warn(string format, params object[] args)
{
Warn(String.Format(format, args));
@ -147,6 +113,7 @@ namespace TShockAPI
/// Writes an informative string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Info")]
public static void Info(String message)
{
Write(message, LogLevel.Info);
@ -157,6 +124,7 @@ namespace TShockAPI
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Info")]
public static void Info(string format, params object[] args)
{
Info(String.Format(format, args));
@ -166,6 +134,7 @@ namespace TShockAPI
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.ConsoleInfo")]
public static void ConsoleInfo(String message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
@ -179,6 +148,7 @@ namespace TShockAPI
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.ConsoleInfo")]
public static void ConsoleInfo(string format, params object[] args)
{
ConsoleInfo(String.Format(format, args));
@ -188,6 +158,7 @@ namespace TShockAPI
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
[Obsolete("Please use TShock.Log.Debug")]
public static void Debug(String message)
{
Write(message, LogLevel.Debug);
@ -198,6 +169,7 @@ namespace TShockAPI
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
[Obsolete("Please use TShock.Log.Debug")]
public static void Debug(string format, params object[] args)
{
Debug(String.Format(format, args));
@ -208,7 +180,7 @@ namespace TShockAPI
/// </summary>
public static void Dispose()
{
_logWriter.Dispose();
TShock.Log.Dispose();
}
/// <summary>
@ -216,35 +188,7 @@ namespace TShockAPI
/// </summary>
private static void Write(String message, LogLevel level)
{
if (!MayWriteType(level))
{
return;
}
string caller = "TShock";
StackFrame frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null)
caller = meth.DeclaringType.Name;
}
try
{
_logWriter.WriteLine(string.Format("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message));
_logWriter.Flush();
}
catch (ObjectDisposedException)
{
Console.WriteLine("Unable to write to log as log has been disposed.");
Console.WriteLine("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message);
}
TShock.Log.Write(message, level);
}
}
}

View file

@ -145,7 +145,7 @@ namespace TShockAPI
}
catch (Exception e)
{
Log.ConsoleError(e.ToString());
TShock.Log.ConsoleError(e.ToString());
}
return false;
}
@ -206,7 +206,7 @@ namespace TShockAPI
}
catch (ObjectDisposedException e)
{
Log.Warn(e.ToString());
TShock.Log.Warn(e.ToString());
}
catch (SocketException e)
{
@ -216,7 +216,7 @@ namespace TShockAPI
case 10053:
break;
default:
Log.Warn(e.ToString());
TShock.Log.Warn(e.ToString());
break;
}
}
@ -230,12 +230,12 @@ namespace TShockAPI
case SocketError.ConnectionReset:
break;
default:
Log.Warn(e.ToString());
TShock.Log.Warn(e.ToString());
break;
}
}
else
Log.Warn(e.ToString());
TShock.Log.Warn(e.ToString());
}
return false;
}

248
TShockAPI/SqlLog.cs Normal file
View file

@ -0,0 +1,248 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using TShockAPI.DB;
namespace TShockAPI
{
/// <summary>
/// Class inheriting ILog for writing logs to TShock's SQL database
/// </summary>
public class SqlLog : ILog, IDisposable
{
private readonly LogLevel _logLevel;
private readonly IDbConnection _database;
private readonly TextLog _backupLog;
private int _failures;
private bool _useTextLog;
public string Name
{
get { return "SQL Log Writer"; }
}
public bool Sql
{
get { return true; }
}
public SqlLog(LogLevel logLevel, IDbConnection db, string textlogFilepath, bool clearTextLog)
{
_logLevel = logLevel;
_database = db;
_backupLog = new TextLog(textlogFilepath, logLevel, clearTextLog);
}
public bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Data(String message)
{
Write(message, LogLevel.Data);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Data(string format, params object[] args)
{
Data(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Error(String message)
{
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Error(string format, params object[] args)
{
Error(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleError(String message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleError(string format, params object[] args)
{
ConsoleError(String.Format(format, args));
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Warn(String message)
{
Write(message, LogLevel.Warning);
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Warn(string format, params object[] args)
{
Warn(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Info(String message)
{
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Info(string format, params object[] args)
{
Info(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleInfo(String message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleInfo(string format, params object[] args)
{
ConsoleInfo(String.Format(format, args));
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Debug(String message)
{
Write(message, LogLevel.Debug);
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Debug(string format, params object[] args)
{
Debug(String.Format(format, args));
}
public void Write(string message, LogLevel level)
{
if (!MayWriteType(level))
return;
var caller = "TShock";
var frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null && meth.DeclaringType != null)
caller = meth.DeclaringType.Name;
}
try
{
if (_useTextLog)
{
_backupLog.Write(message, level);
return;
}
_database.Query("INSERT INTO Logs (LogLevel, TimeStamp, Caller, Message) VALUES (@0, @1, @2, @3)",
level, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, message);
if (_failures > 0)
_failures--;
}
catch (Exception ex)
{
_backupLog.ConsoleError("SQL Log insert query failed: {0}", ex);
_failures++;
_backupLog.Error("SQL logging will revert to text logging if {0} more failures occur.",
TShock.Config.RevertToTextLogsOnSqlFailures - _failures);
if (_failures >= TShock.Config.RevertToTextLogsOnSqlFailures)
{
_useTextLog = true;
_backupLog.ConsoleError("SQL Logging disabled due to errors. Reverting to text logging.");
}
}
}
public void Dispose()
{
_backupLog.Dispose();
}
}
}

View file

@ -36,8 +36,6 @@ using Terraria;
using TerrariaApi.Server;
using TShockAPI.DB;
using TShockAPI.Net;
using System.Threading;
using System.Threading.Tasks;
using TShockAPI.ServerSideCharacters;
namespace TShockAPI
@ -53,7 +51,7 @@ namespace TShockAPI
private static string LogFormat = LogFormatDefault;
private const string LogPathDefault = "tshock";
private static string LogPath = LogPathDefault;
private static bool LogClear = false;
private static bool LogClear;
public static TSPlayer[] Players = new TSPlayer[Main.maxPlayers];
public static BanManager Bans;
@ -77,6 +75,7 @@ namespace TShockAPI
public static RestManager RestManager;
public static Utils Utils = Utils.Instance;
public static UpdateManager UpdateManager;
public static ILog Log;
/// <summary>
/// Used for implementing REST Tokens prior to the REST system starting up.
/// </summary>
@ -126,6 +125,9 @@ namespace TShockAPI
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
public override void Initialize()
{
string logFilename;
string logPathSetupWarning;
try
{
HandleCommandLine(Environment.GetCommandLineArgs());
@ -142,37 +144,29 @@ namespace TShockAPI
Main.ServerSideCharacter = ServerSideCharacterConfig.Enabled;
DateTime now = DateTime.Now;
string logFilename;
string logPathSetupWarning = null;
// Log path was not already set by the command line parameter?
if (LogPath == LogPathDefault)
LogPath = Config.LogPath;
try
{
logFilename = Path.Combine(LogPath, now.ToString(LogFormat)+".log");
logFilename = Path.Combine(LogPath, now.ToString(LogFormat) + ".log");
if (!Directory.Exists(LogPath))
Directory.CreateDirectory(LogPath);
}
catch(Exception ex)
catch (Exception ex)
{
logPathSetupWarning = "Could not apply the given log path / log format, defaults will be used. Exception details:\n" + ex;
logPathSetupWarning =
"Could not apply the given log path / log format, defaults will be used. Exception details:\n" + ex;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(logPathSetupWarning);
Console.ForegroundColor = ConsoleColor.Gray;
// Problem with the log path or format use the default
logFilename = Path.Combine(LogPathDefault, now.ToString(LogFormatDefault) + ".log");
}
#if DEBUG
Log.Initialize(logFilename, LogLevel.All, false);
#else
Log.Initialize(logFilename, LogLevel.All & ~LogLevel.Debug, LogClear);
#endif
if (logPathSetupWarning != null)
Log.Warn(logPathSetupWarning);
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
catch(Exception ex)
catch (Exception ex)
{
// Will be handled by the server api and written to its crashlog.txt.
throw new Exception("Fatal TShock initialization exception. See inner exception for details.", ex);
@ -181,16 +175,6 @@ namespace TShockAPI
// Further exceptions are written to TShock's log from now on.
try
{
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
Log.ConsoleInfo(
"TShock was improperly shut down. Please use the exit command in the future to prevent this.");
File.Delete(Path.Combine(SavePath, "tshock.pid"));
}
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"), Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture));
HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
if (Config.StorageType.ToLower() == "sqlite")
{
string sql = Path.Combine(SavePath, "tshock.sqlite");
@ -213,7 +197,9 @@ namespace TShockAPI
}
catch (MySqlException ex)
{
Log.Error(ex.ToString());
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex);
Console.ResetColor();
throw new Exception("MySql not setup correctly");
}
}
@ -222,6 +208,28 @@ namespace TShockAPI
throw new Exception("Invalid storage type");
}
#if DEBUG
var level = LogLevel.All;
#else
var level = LogLevel.All & ~LogLevel.Debug;
#endif
if (Config.UseSqlLogs)
Log = new SqlLog(level, DB, logFilename, LogClear);
else
Log = new TextLog(logFilename, level, LogClear);
if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
{
Log.ConsoleInfo(
"TShock was improperly shut down. Please use the exit command in the future to prevent this.");
File.Delete(Path.Combine(SavePath, "tshock.pid"));
}
File.WriteAllText(Path.Combine(SavePath, "tshock.pid"),
Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture));
HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
Backups = new BackupManager(Path.Combine(SavePath, "backups"));
Backups.KeepFor = Config.BackupKeepFor;
Backups.Interval = Config.BackupInterval;
@ -1210,24 +1218,24 @@ namespace TShockAPI
player.LoginMS = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
if (TShock.Config.EnableGeoIP && TShock.Geo != null)
if (Config.EnableGeoIP && TShock.Geo != null)
{
Log.Info(string.Format("{0} ({1}) from '{2}' group from '{3}' joined. ({4}/{5})", player.Name, player.IP,
player.Group.Name, player.Country, TShock.Utils.ActivePlayers(),
TShock.Config.MaxSlots));
if (!player.SilentJoinInProgress)
TShock.Utils.Broadcast(string.Format("{0} ({1}) has joined.", player.Name, player.Country), Color.Yellow);
Utils.Broadcast(string.Format("{0} ({1}) has joined.", player.Name, player.Country), Color.Yellow);
}
else
{
Log.Info(string.Format("{0} ({1}) from '{2}' group joined. ({3}/{4})", player.Name, player.IP,
player.Group.Name, TShock.Utils.ActivePlayers(), TShock.Config.MaxSlots));
if (!player.SilentJoinInProgress)
TShock.Utils.Broadcast(player.Name + " has joined.", Color.Yellow);
Utils.Broadcast(player.Name + " has joined.", Color.Yellow);
}
if (TShock.Config.DisplayIPToAdmins)
TShock.Utils.SendLogs(string.Format("{0} has joined. IP: {1}", player.Name, player.IP), Color.Blue);
if (Config.DisplayIPToAdmins)
Utils.SendLogs(string.Format("{0} has joined. IP: {1}", player.Name, player.IP), Color.Blue);
Utils.ShowFileToUser(player, "motd.txt");

View file

@ -78,6 +78,10 @@
<Compile Include="Hooks\AccountHooks.cs" />
<Compile Include="Hooks\GeneralHooks.cs" />
<Compile Include="Hooks\PlayerHooks.cs" />
<Compile Include="ILog.cs" />
<Compile Include="Log.cs" />
<Compile Include="SqlLog.cs" />
<Compile Include="TextLog.cs" />
<Compile Include="PaginationTools.cs" />
<Compile Include="Rest\RestPermissions.cs" />
<Compile Include="SaveManager.cs" />
@ -102,7 +106,6 @@
<Compile Include="GetDataHandlers.cs" />
<Compile Include="Group.cs" />
<Compile Include="Extensions\LinqExt.cs" />
<Compile Include="Log.cs" />
<Compile Include="Net\BaseMsg.cs" />
<Compile Include="Net\DisconnectMsg.cs" />
<Compile Include="Net\NetTile.cs" />
@ -182,7 +185,7 @@
</PropertyGroup>
<ProjectExtensions>
<VisualStudio>
<UserProperties BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" BuildVersion_BuildAction="Both" BuildVersion_BuildVersioningStyle="None.None.None.MonthAndDayStamp" BuildVersion_StartDate="2011/6/17" BuildVersion_IncrementBeforeBuild="False" />
<UserProperties BuildVersion_IncrementBeforeBuild="False" BuildVersion_StartDate="2011/6/17" BuildVersion_BuildVersioningStyle="None.None.None.MonthAndDayStamp" BuildVersion_BuildAction="Both" BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" />
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

250
TShockAPI/TextLog.cs Normal file
View file

@ -0,0 +1,250 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2015 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
namespace TShockAPI
{
/// <summary>
/// Class inheriting ILog for writing logs to a text file
/// </summary>
public class TextLog : ILog, IDisposable
{
private readonly StreamWriter _logWriter;
private readonly LogLevel _logLevel;
/// <summary>
/// Log file name
/// </summary>
public static string fileName { get; private set; }
/// <summary>
/// Name of the TextLog
/// </summary>
public string Name
{
get { return "Text Log Writer"; }
}
public bool Sql
{
get { return false; }
}
/// <summary>
/// Creates the log file stream and sets the initial log level.
/// </summary>
/// <param name="filename">The output filename. This file will be overwritten if 'clear' is set.</param>
/// <param name="logLevel">The <see cref="LogLevel" /> value which sets the type of messages to output.</param>
/// <param name="clear">Whether or not to clear the log file on initialization.</param>
public TextLog(string filename, LogLevel logLevel, bool clear)
{
fileName = filename;
_logLevel = logLevel;
_logWriter = new StreamWriter(filename, !clear);
}
public bool MayWriteType(LogLevel type)
{
return ((_logLevel & type) == type);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Data(String message)
{
Write(message, LogLevel.Data);
}
/// <summary>
/// Writes data to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Data(string format, params object[] args)
{
Data(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Error(String message)
{
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Error(string format, params object[] args)
{
Error(String.Format(format, args));
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleError(String message)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Error);
}
/// <summary>
/// Writes an error to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleError(string format, params object[] args)
{
ConsoleError(String.Format(format, args));
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Warn(String message)
{
Write(message, LogLevel.Warning);
}
/// <summary>
/// Writes a warning to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Warn(string format, params object[] args)
{
Warn(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Info(String message)
{
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Info(string format, params object[] args)
{
Info(String.Format(format, args));
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="message">The message to be written.</param>
public void ConsoleInfo(String message)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(message);
Console.ForegroundColor = ConsoleColor.Gray;
Write(message, LogLevel.Info);
}
/// <summary>
/// Writes an informative string to the log file. Also outputs to the console.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void ConsoleInfo(string format, params object[] args)
{
ConsoleInfo(String.Format(format, args));
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="message">The message to be written.</param>
public void Debug(String message)
{
Write(message, LogLevel.Debug);
}
/// <summary>
/// Writes a debug string to the log file.
/// </summary>
/// <param name="format">The format of the message to be written.</param>
/// <param name="args">The format arguments.</param>
public void Debug(string format, params object[] args)
{
Debug(String.Format(format, args));
}
/// <summary>
/// Writes a message to the log
/// </summary>
/// <param name="message"></param>
/// <param name="level"></param>
public void Write(string message, LogLevel level)
{
if (!MayWriteType(level))
return;
var caller = "TShock";
var frame = new StackTrace().GetFrame(2);
if (frame != null)
{
var meth = frame.GetMethod();
if (meth != null && meth.DeclaringType != null)
caller = meth.DeclaringType.Name;
}
try
{
_logWriter.WriteLine("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message);
_logWriter.Flush();
}
catch (ObjectDisposedException)
{
Console.WriteLine("Unable to write to log as log has been disposed.");
Console.WriteLine("{0} - {1}: {2}: {3}",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture),
caller, level.ToString().ToUpper(), message);
}
}
public void Dispose()
{
_logWriter.Dispose();
}
}
}