From 0459dfca11e3c0adc190f650b4fe7e4b2656e6c3 Mon Sep 17 00:00:00 2001 From: Lucas Nicodemus Date: Wed, 25 Feb 2015 14:52:28 -0700 Subject: [PATCH] Adds SQL logging from WhiteX's fork; closes #869 --- TShockAPI/BackupManager.cs | 6 +- TShockAPI/Commands.cs | 46 +++---- TShockAPI/ConfigFile.cs | 6 + TShockAPI/ILog.cs | 140 ++++++++++++++++++++ TShockAPI/Log.cs | 88 +++---------- TShockAPI/PacketBufferer.cs | 10 +- TShockAPI/SqlLog.cs | 248 +++++++++++++++++++++++++++++++++++ TShockAPI/TShock.cs | 86 +++++++------ TShockAPI/TShockAPI.csproj | 7 +- TShockAPI/TextLog.cs | 250 ++++++++++++++++++++++++++++++++++++ 10 files changed, 743 insertions(+), 144 deletions(-) create mode 100644 TShockAPI/ILog.cs create mode 100644 TShockAPI/SqlLog.cs create mode 100644 TShockAPI/TextLog.cs diff --git a/TShockAPI/BackupManager.cs b/TShockAPI/BackupManager.cs index 1882d0bb..5422160e 100644 --- a/TShockAPI/BackupManager.cs +++ b/TShockAPI/BackupManager.cs @@ -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()); } } diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index b7829574..fe911e99 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -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) diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs index be24b8b8..f0068762 100755 --- a/TShockAPI/ConfigFile.cs +++ b/TShockAPI/ConfigFile.cs @@ -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; diff --git a/TShockAPI/ILog.cs b/TShockAPI/ILog.cs new file mode 100644 index 00000000..906498ce --- /dev/null +++ b/TShockAPI/ILog.cs @@ -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 . +*/ + +using System; + +namespace TShockAPI +{ + [Flags] + public enum LogLevel + { + None = 0, + Debug = 1, + Info = 2, + Warning = 4, + Error = 8, + Data = 16, + All = 31 + } + + /// + /// Logging interface + /// + public interface ILog + { + /// + /// Log name + /// + string Name { get; } + + /// + /// Returns true if the ILog is using SQL or false if not + /// + bool Sql { get; } + + /// + /// Checks whether the log level contains the specified flag. + /// + /// The value to check. + bool MayWriteType(LogLevel type); + + /// + /// Writes an informative string to the log and to the console. + /// + /// The message to be written. + void ConsoleInfo(string message); + /// + /// Writes an informative string to the log and to the console. + /// + /// The format of the message to be written. + /// The format arguments. + void ConsoleInfo(string format, params object[] args); + + /// + /// Writes an error message to the log and to the console. + /// + /// The message to be written. + void ConsoleError(string message); + /// + /// Writes an error message to the log and to the console. + /// + /// The format of the message to be written. + /// The format arguments. + void ConsoleError(string format, params object[] args); + + /// + /// Writes a warning to the log. + /// + /// The message to be written. + void Warn(string message); + /// + /// Writes a warning to the log. + /// + /// The format of the message to be written. + /// The format arguments. + void Warn(string format, params object[] args); + + /// + /// Writes an error to the log. + /// + /// The message to be written. + void Error(string message); + /// + /// Writes an error to the log. + /// + /// The format of the message to be written. + /// The format arguments. + void Error(string format, params object[] args); + + /// + /// Writes an informative string to the log. + /// + /// The message to be written. + void Info(string message); + /// + /// Writes an informative string to the log. + /// + /// The format of the message to be written. + /// The format arguments. + void Info(string format, params object[] args); + + /// + /// Writes data to the log. + /// + /// The message to be written. + void Data(string message); + /// + /// Writes data to the log. + /// + /// The format of the message to be written. + /// The format arguments. + void Data(string format, params object[] args); + + /// + /// Writes a message to the log + /// + /// Message to write + /// LogLevel assosciated with the message + void Write(string message, LogLevel level); + + /// + /// Dispose the Log + /// + void Dispose(); + } +} diff --git a/TShockAPI/Log.cs b/TShockAPI/Log.cs index 27d4f512..782dbe36 100644 --- a/TShockAPI/Log.cs +++ b/TShockAPI/Log.cs @@ -17,57 +17,16 @@ along with this program. If not, see . */ 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; - - /// - /// Creates the log file stream and sets the initial log level. - /// - /// The output filename. This file will be overwritten if 'clear' is set. - /// The value which sets the type of messages to output. - /// Whether or not to clear the log file on initialization. - public static void Initialize(string filename, LogLevel logLevel, bool clear) - { - _filename = filename; - _logLevel = logLevel; - - _logWriter = new StreamWriter(filename, !clear); - } - - /// - /// Checks whether the log level contains the specified flag. - /// - /// The value to check. - private static bool MayWriteType(LogLevel type) - { - return ((_logLevel & type) == type); - } - /// /// Writes data to the log file. /// /// The message to be written. + [Obsolete("Please use TShock.Log.Data")] public static void Data(String message) { Write(message, LogLevel.Data); @@ -78,6 +37,7 @@ namespace TShockAPI /// /// The format of the message to be written. /// The format arguments. + [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. /// /// The message to be written. + [Obsolete("Please use TShock.Log.Error")] public static void Error(String message) { Write(message, LogLevel.Error); @@ -97,6 +58,7 @@ namespace TShockAPI /// /// The format of the message to be written. /// The format arguments. + [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. /// /// The message to be written. + [Obsolete("Please use TShock.Log.ConsoleError")] public static void ConsoleError(String message) { Console.ForegroundColor = ConsoleColor.Red; @@ -119,6 +82,7 @@ namespace TShockAPI /// /// The format of the message to be written. /// The format arguments. + [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. /// /// The message to be written. + [Obsolete("Please use TShock.Log.Warn")] public static void Warn(String message) { Write(message, LogLevel.Warning); @@ -138,6 +103,7 @@ namespace TShockAPI /// /// The format of the message to be written. /// The format arguments. + [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. /// /// The message to be written. + [Obsolete("Please use TShock.Log.Info")] public static void Info(String message) { Write(message, LogLevel.Info); @@ -157,6 +124,7 @@ namespace TShockAPI /// /// The format of the message to be written. /// The format arguments. + [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. /// /// The message to be written. + [Obsolete("Please use TShock.Log.ConsoleInfo")] public static void ConsoleInfo(String message) { Console.ForegroundColor = ConsoleColor.Yellow; @@ -179,6 +148,7 @@ namespace TShockAPI /// /// The format of the message to be written. /// The format arguments. + [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. /// /// The message to be written. + [Obsolete("Please use TShock.Log.Debug")] public static void Debug(String message) { Write(message, LogLevel.Debug); @@ -198,6 +169,7 @@ namespace TShockAPI /// /// The format of the message to be written. /// The format arguments. + [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 /// public static void Dispose() { - _logWriter.Dispose(); + TShock.Log.Dispose(); } /// @@ -216,35 +188,7 @@ namespace TShockAPI /// 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); } } } \ No newline at end of file diff --git a/TShockAPI/PacketBufferer.cs b/TShockAPI/PacketBufferer.cs index 051a9531..5d420618 100644 --- a/TShockAPI/PacketBufferer.cs +++ b/TShockAPI/PacketBufferer.cs @@ -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; } diff --git a/TShockAPI/SqlLog.cs b/TShockAPI/SqlLog.cs new file mode 100644 index 00000000..8aed014f --- /dev/null +++ b/TShockAPI/SqlLog.cs @@ -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 . +*/ + +using System; +using System.Data; +using System.Diagnostics; +using System.Globalization; +using TShockAPI.DB; + +namespace TShockAPI +{ + /// + /// Class inheriting ILog for writing logs to TShock's SQL database + /// + 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); + } + + /// + /// Writes data to the log file. + /// + /// The message to be written. + public void Data(String message) + { + Write(message, LogLevel.Data); + } + + /// + /// Writes data to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public void Data(string format, params object[] args) + { + Data(String.Format(format, args)); + } + + /// + /// Writes an error to the log file. + /// + /// The message to be written. + public void Error(String message) + { + Write(message, LogLevel.Error); + } + + /// + /// Writes an error to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public void Error(string format, params object[] args) + { + Error(String.Format(format, args)); + } + + /// + /// Writes an error to the log file. + /// + /// The message to be written. + public void ConsoleError(String message) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(message); + Console.ForegroundColor = ConsoleColor.Gray; + Write(message, LogLevel.Error); + } + + /// + /// Writes an error to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public void ConsoleError(string format, params object[] args) + { + ConsoleError(String.Format(format, args)); + } + + /// + /// Writes a warning to the log file. + /// + /// The message to be written. + public void Warn(String message) + { + Write(message, LogLevel.Warning); + } + + /// + /// Writes a warning to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public void Warn(string format, params object[] args) + { + Warn(String.Format(format, args)); + } + + /// + /// Writes an informative string to the log file. + /// + /// The message to be written. + public void Info(String message) + { + Write(message, LogLevel.Info); + } + + /// + /// Writes an informative string to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + public void Info(string format, params object[] args) + { + Info(String.Format(format, args)); + } + + /// + /// Writes an informative string to the log file. Also outputs to the console. + /// + /// The message to be written. + public void ConsoleInfo(String message) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(message); + Console.ForegroundColor = ConsoleColor.Gray; + Write(message, LogLevel.Info); + } + + /// + /// Writes an informative string to the log file. Also outputs to the console. + /// + /// The format of the message to be written. + /// The format arguments. + public void ConsoleInfo(string format, params object[] args) + { + ConsoleInfo(String.Format(format, args)); + } + + /// + /// Writes a debug string to the log file. + /// + /// The message to be written. + public void Debug(String message) + { + Write(message, LogLevel.Debug); + } + + /// + /// Writes a debug string to the log file. + /// + /// The format of the message to be written. + /// The format arguments. + 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(); + } + } +} \ No newline at end of file diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 436acbea..5c0df0b5 100755 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -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; /// /// Used for implementing REST Tokens prior to the REST system starting up. /// @@ -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"); @@ -204,16 +188,18 @@ namespace TShockAPI DB = new MySqlConnection(); DB.ConnectionString = String.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};", - hostport[0], - hostport.Length > 1 ? hostport[1] : "3306", - Config.MySqlDbName, - Config.MySqlUsername, - Config.MySqlPassword + hostport[0], + hostport.Length > 1 ? hostport[1] : "3306", + Config.MySqlDbName, + Config.MySqlUsername, + Config.MySqlPassword ); } catch (MySqlException ex) { - Log.Error(ex.ToString()); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(ex); + Console.ResetColor(); throw new Exception("MySql not setup correctly"); } } @@ -222,12 +208,34 @@ 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; Bans = new BanManager(DB); Warps = new WarpManager(DB); - Regions = new RegionManager(DB); + Regions = new RegionManager(DB); Users = new UserManager(DB); Groups = new GroupManager(DB); Itembans = new ItemManager(DB); @@ -294,7 +302,7 @@ namespace TShockAPI } } - private static void getTShockAscii() + private static void getTShockAscii() { // ReSharper disable LocalizableElement Console.Write(" ___ ___ ___ ___ ___ \n" + @@ -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"); diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index 4072b8ed..e038bbaa 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -78,6 +78,10 @@ + + + + @@ -102,7 +106,6 @@ - @@ -182,7 +185,7 @@ - +