Terraria ModLoader  0.11.1
A framework for Terraria mods
Terraria.ModLoader.Logging Class Reference
+ Collaboration diagram for Terraria.ModLoader.Logging:

Static Public Member Functions

static void IgnoreExceptionContents (string source)
 
static void IgnoreExceptionSource (string source)
 
static void PrettifyStackTraceSources (StackFrame[] frames)
 

Static Public Attributes

static readonly string LogDir = Path.Combine(Program.SavePath, "Logs")
 

Properties

static string LogPath [get, private set]
 

Private Member Functions

delegate void ctor_StackTrace (StackTrace self, Exception e, bool fNeedFileInfo)
 
delegate string hook_GetStackTrace (orig_GetStackTrace orig, Exception self, bool fNeedFileInfo)
 
delegate void hook_StackTrace (ctor_StackTrace orig, StackTrace self, Exception e, bool fNeedFileInfo)
 
delegate string orig_GetStackTrace (Exception self, bool fNeedFileInfo)
 
delegate EventHandler SendRequest (object self, HttpWebRequest request)
 
delegate EventHandler SendRequestHook (SendRequest orig, object self, HttpWebRequest request)
 
delegate bool SubmitRequest (object self, HttpWebRequest request, bool forcedsubmit)
 
delegate bool SubmitRequestHook (SubmitRequest orig, object self, HttpWebRequest request, bool forcedsubmit)
 
delegate void WebOperation_ctor (object self, HttpWebRequest request, object writeBuffer, bool isNtlmChallenge, CancellationToken cancellationToken)
 
delegate void WebOperation_ctorHook (WebOperation_ctor orig, object self, HttpWebRequest request, object writeBuffer, bool isNtlmChallenge, CancellationToken cancellationToken)
 

Static Private Member Functions

static void AddChatMessage (string msg, Color color)
 
static void Archive (string logPath)
 
static bool CanOpen (string fileName)
 
static void ConfigureAppenders ()
 
static void DeleteOldArchives ()
 
static void EnablePortablePDBTraces ()
 
static void FirstChanceExceptionHandler (object sender, FirstChanceExceptionEventArgs args)
 
static string HookGetStackTrace (orig_GetStackTrace orig, Exception self, bool fNeedFileInfo)
 
static void HookStackTraceEx (ctor_StackTrace orig, StackTrace self, Exception e, bool fNeedFileInfo)
 
static void HookWebRequests ()
 Attempt to hook the .NET internal methods to log when requests are sent to web addresses. Use the right internal methods to capture redirects More...
 
static void LogFirstChanceExceptions ()
 
static void PrettifyStackTraceSources ()
 
static string RollLogs (string baseName)
 

Private Attributes

const int MAX_LOGS = 20
 

Static Private Attributes

static readonly Regex dropGenericTicks = new Regex(@"`\d+", RegexOptions.Compiled)
 
static readonly Regex dropOffset = new Regex(@" \[.+?\](?![^:]+:-1)", RegexOptions.Compiled)
 
static List< string > ignoreContents
 
static List< string > ignoreMessages
 
static HashSet< string > ignoreSources
 
static HashSet< string > pastExceptions = new HashSet<string>()
 
static Exception previousException
 
static Regex statusRegex = new Regex(@"(.+?)[: \d]*%$")
 
static readonly Assembly TerrariaAssembly = Assembly.GetExecutingAssembly()
 
static readonly Regex trimParamTypes = new Regex(@"([([,] ?)(?:[\w.+]+[.+])", RegexOptions.Compiled)
 

Detailed Description

Definition at line 26 of file Logging.cs.

Member Function Documentation

◆ AddChatMessage()

static void Terraria.ModLoader.Logging.AddChatMessage ( string  msg,
Color  color 
)
staticprivate

Definition at line 290 of file Logging.cs.

290  {
291  if (Main.gameMenu)
292  return;
293 
294  float soundVolume = Main.soundVolume;
295  Main.soundVolume = 0f;
296  Main.NewText(msg, color);
297  Main.soundVolume = soundVolume;
298  }

◆ Archive()

static void Terraria.ModLoader.Logging.Archive ( string  logPath)
staticprivate

Definition at line 128 of file Logging.cs.

128  {
129  var time = File.GetCreationTime(logPath);
130  int n = 1;
131 
132  var pattern = new Regex($"{time:yyyy-MM-dd}-(\\d+)\\.zip");
133  var existingLogs = Directory.GetFiles(LogDir).Where(s => pattern.IsMatch(Path.GetFileName(s))).ToList();
134  if (existingLogs.Count > 0)
135  n = existingLogs.Select(s => int.Parse(pattern.Match(Path.GetFileName(s)).Groups[1].Value)).Max() + 1;
136 
137  using (var zip = new ZipFile(Path.Combine(LogDir, $"{time:yyyy-MM-dd}-{n}.zip"), Encoding.UTF8)) {
138  zip.AddFile(logPath, "");
139  zip.Save();
140  }
141 
142  File.Delete(logPath);
143  }
static readonly string LogDir
Definition: Logging.cs:28

◆ CanOpen()

static bool Terraria.ModLoader.Logging.CanOpen ( string  fileName)
staticprivate

Definition at line 118 of file Logging.cs.

118  {
119  try {
120  using (new FileStream(fileName, FileMode.Append)) ;
121  return true;
122  }
123  catch (IOException) {
124  return false;
125  }
126  }

◆ ConfigureAppenders()

static void Terraria.ModLoader.Logging.ConfigureAppenders ( )
staticprivate

Definition at line 66 of file Logging.cs.

66  {
67  var layout = new PatternLayout {
68  ConversionPattern = "[%d{HH:mm:ss}] [%t/%level] [%logger]: %m%n"
69  };
70  layout.ActivateOptions();
71 
72  var appenders = new List<IAppender>();
73 #if CLIENT
74  appenders.Add(new ConsoleAppender {
75  Name = "ConsoleAppender",
76  Layout = layout
77  });
78 #else
79  appenders.Add(new DebugAppender {
80  Name = "DebugAppender",
81  Layout = layout
82  });
83 #endif
84 
85  var fileAppender = new FileAppender {
86  Name = "FileAppender",
87  File = LogPath = Path.Combine(LogDir, RollLogs(side)),
88  AppendToFile = false,
89  Encoding = Encoding.UTF8,
90  Layout = layout
91  };
92  fileAppender.ActivateOptions();
93  appenders.Add(fileAppender);
94 
95  BasicConfigurator.Configure(appenders.ToArray());
96  }
static string LogPath
Definition: Logging.cs:29
static string RollLogs(string baseName)
Definition: Logging.cs:98
static readonly string LogDir
Definition: Logging.cs:28

◆ ctor_StackTrace()

delegate void Terraria.ModLoader.Logging.ctor_StackTrace ( StackTrace  self,
Exception  e,
bool  fNeedFileInfo 
)
private

◆ DeleteOldArchives()

static void Terraria.ModLoader.Logging.DeleteOldArchives ( )
staticprivate

Definition at line 146 of file Logging.cs.

146  {
147  var pattern = new Regex(".*\\.zip");
148  var existingLogs = Directory.GetFiles(LogDir).Where(s => pattern.IsMatch(Path.GetFileName(s))).OrderBy(File.GetCreationTime).ToList();
149  foreach (var f in existingLogs.Take(existingLogs.Count - MAX_LOGS)) {
150  try {
151  File.Delete(f);
152  }
153  catch (IOException) { }
154  }
155  }
static readonly string LogDir
Definition: Logging.cs:28

◆ EnablePortablePDBTraces()

static void Terraria.ModLoader.Logging.EnablePortablePDBTraces ( )
staticprivate

Definition at line 392 of file Logging.cs.

References Terraria.ModLoader.FrameworkVersion.Framework, and Terraria.ModLoader.FrameworkVersion.Version.

392  {
393  if (FrameworkVersion.Framework == Framework.NetFramework && FrameworkVersion.Version >= new Version(4, 7, 2))
394  Type.GetType("System.AppContextSwitches").GetField("_ignorePortablePDBsInStackTraces", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, -1);
395  }

◆ FirstChanceExceptionHandler()

static void Terraria.ModLoader.Logging.FirstChanceExceptionHandler ( object  sender,
FirstChanceExceptionEventArgs  args 
)
staticprivate

Definition at line 255 of file Logging.cs.

References Terraria.ModLoader.Console.

255  {
256  if (args.Exception == previousException ||
257  args.Exception is ThreadAbortException ||
258  ignoreSources.Contains(args.Exception.Source) ||
259  ignoreMessages.Any(str => args.Exception.Message.Contains(str)))
260  return;
261 
262  var stackTrace = new StackTrace(true);
263  PrettifyStackTraceSources(stackTrace.GetFrames());
264  var traceString = stackTrace.ToString();
265 
266  if (ignoreContents.Any(traceString.Contains))
267  return;
268 
269  traceString = traceString.Substring(traceString.IndexOf('\n'));
270  var exString = args.Exception.GetType() + ": " + args.Exception.Message + traceString;
271  lock (pastExceptions) {
272  if (!pastExceptions.Add(exString))
273  return;
274  }
275 
276  previousException = args.Exception;
277  var msg = args.Exception.Message + " " + Language.GetTextValue("tModLoader.RuntimeErrorSeeLogsForFullTrace", Path.GetFileName(LogPath));
278 #if CLIENT
279  if (ModCompile.activelyModding)
280  AddChatMessage(msg, Color.OrangeRed);
281 #else
282  Console.ForegroundColor = ConsoleColor.DarkMagenta;
283  Console.WriteLine(msg);
284  Console.ResetColor();
285 #endif
286  tML.Warn(Language.GetTextValue("tModLoader.RuntimeErrorSilentlyCaughtException") + '\n' + exString);
287  }
static string LogPath
Definition: Logging.cs:29
static List< string > ignoreContents
Definition: Logging.cs:229
static List< string > ignoreMessages
Definition: Logging.cs:240
Command can be used in server console during MP.
static HashSet< string > ignoreSources
Definition: Logging.cs:224
static HashSet< string > pastExceptions
Definition: Logging.cs:221
static Exception previousException
Definition: Logging.cs:254
static void AddChatMessage(string msg, Color color)
Definition: Logging.cs:290
static void PrettifyStackTraceSources()
Definition: Logging.cs:382

◆ hook_GetStackTrace()

delegate string Terraria.ModLoader.Logging.hook_GetStackTrace ( orig_GetStackTrace  orig,
Exception  self,
bool  fNeedFileInfo 
)
private

◆ hook_StackTrace()

delegate void Terraria.ModLoader.Logging.hook_StackTrace ( ctor_StackTrace  orig,
StackTrace  self,
Exception  e,
bool  fNeedFileInfo 
)
private

◆ HookGetStackTrace()

static string Terraria.ModLoader.Logging.HookGetStackTrace ( orig_GetStackTrace  orig,
Exception  self,
bool  fNeedFileInfo 
)
staticprivate

Definition at line 344 of file Logging.cs.

344  {
345  var stackTrace = new StackTrace(self, true);
346  MdbManager.Symbolize(stackTrace.GetFrames());
347  PrettifyStackTraceSources(stackTrace.GetFrames());
348  var s = stackTrace.ToString();
349  s = trimParamTypes.Replace(s, "$1");
350  s = dropGenericTicks.Replace(s, "");
351  s = dropOffset.Replace(s, "");
352  s = s.Replace(":-1", "");
353  return s;
354  }
static readonly Regex dropOffset
Definition: Logging.cs:339
static readonly Regex trimParamTypes
Definition: Logging.cs:338
static readonly Regex dropGenericTicks
Definition: Logging.cs:340
static void PrettifyStackTraceSources()
Definition: Logging.cs:382

◆ HookStackTraceEx()

static void Terraria.ModLoader.Logging.HookStackTraceEx ( ctor_StackTrace  orig,
StackTrace  self,
Exception  e,
bool  fNeedFileInfo 
)
staticprivate

Definition at line 331 of file Logging.cs.

331  {
332  orig(self, e, fNeedFileInfo);
333  if (fNeedFileInfo)
334  PrettifyStackTraceSources(self.GetFrames());
335  }
static void PrettifyStackTraceSources()
Definition: Logging.cs:382

◆ HookWebRequests()

static void Terraria.ModLoader.Logging.HookWebRequests ( )
staticprivate

Attempt to hook the .NET internal methods to log when requests are sent to web addresses. Use the right internal methods to capture redirects

Definition at line 170 of file Logging.cs.

171  {
172  try {
173  // .NET 4.7.2
174  MethodBase met = typeof(HttpWebRequest).Assembly
175  .GetType("System.Net.Connection")
176  ?.FindMethod("SubmitRequest");
177  if (met != null) {
178  new Hook(met, new SubmitRequestHook((orig, self, request, forcedsubmit) => {
179  tML.Debug($"Web Request: " + request.Address);
180  return orig(self, request, forcedsubmit);
181  }));
182  return;
183  }
184 
185  // Mono 5.20
186  met = typeof(HttpWebRequest).Assembly
187  .GetType("System.Net.WebOperation")
188  ?.GetConstructors()[0];
189  if (met != null && met.GetParameters().Length == 4) {
190  new Hook(met, new WebOperation_ctorHook((orig, self, request, buffer, challenge, token) => {
191  tML.Debug($"Web Request: " + request.Address);
192  orig(self, request, buffer, challenge, token);
193  }));
194  return;
195  }
196 
197  // Mono 4.6.1
198  met = typeof(HttpWebRequest).Assembly
199  .GetType("System.Net.WebConnection")
200  ?.FindMethod("SendRequest");
201  if (met != null) {
202  new Hook(met, new SendRequestHook((orig, self, request) => {
203  tML.Debug($"Web Request: " + request.Address);
204  return orig(self, request);
205  }));
206  return;
207  }
208  }
209  catch { }
210 
211  tML.Warn("HttpWebRequest send/submit method not found");
212  }
delegate EventHandler SendRequestHook(SendRequest orig, object self, HttpWebRequest request)
delegate void WebOperation_ctorHook(WebOperation_ctor orig, object self, HttpWebRequest request, object writeBuffer, bool isNtlmChallenge, CancellationToken cancellationToken)
delegate bool SubmitRequestHook(SubmitRequest orig, object self, HttpWebRequest request, bool forcedsubmit)

◆ IgnoreExceptionContents()

static void Terraria.ModLoader.Logging.IgnoreExceptionContents ( string  source)
static

Definition at line 249 of file Logging.cs.

249  {
250  if (!ignoreContents.Contains(source))
251  ignoreContents.Add(source);
252  }
static List< string > ignoreContents
Definition: Logging.cs:229

◆ IgnoreExceptionSource()

static void Terraria.ModLoader.Logging.IgnoreExceptionSource ( string  source)
static

◆ LogFirstChanceExceptions()

static void Terraria.ModLoader.Logging.LogFirstChanceExceptions ( )
staticprivate

Definition at line 214 of file Logging.cs.

References Terraria.ModLoader.FrameworkVersion.Framework.

214  {
215  if (FrameworkVersion.Framework == Framework.Mono)
216  tML.Warn("First-chance exception reporting is not implemented on Mono");
217 
218  AppDomain.CurrentDomain.FirstChanceException += FirstChanceExceptionHandler;
219  }
static void FirstChanceExceptionHandler(object sender, FirstChanceExceptionEventArgs args)
Definition: Logging.cs:255

◆ orig_GetStackTrace()

delegate string Terraria.ModLoader.Logging.orig_GetStackTrace ( Exception  self,
bool  fNeedFileInfo 
)
private

◆ PrettifyStackTraceSources() [1/2]

static void Terraria.ModLoader.Logging.PrettifyStackTraceSources ( StackFrame []  frames)
static

Definition at line 356 of file Logging.cs.

356  {
357  if (frames == null)
358  return;
359 
360  foreach (var frame in frames) {
361  string filename = frame.GetFileName();
362  var assembly = frame.GetMethod()?.DeclaringType?.Assembly;
363  if (filename == null || assembly == null)
364  continue;
365 
366  string trim;
367  if (AssemblyManager.GetAssemblyOwner(assembly, out var modName))
368  trim = modName;
369  else if (assembly == TerrariaAssembly)
370  trim = "tModLoader";
371  else
372  continue;
373 
374  int idx = filename.LastIndexOf(trim, StringComparison.InvariantCultureIgnoreCase);
375  if (idx > 0) {
376  filename = filename.Substring(idx);
377  f_fileName.SetValue(frame, filename);
378  }
379  }
380  }
static readonly Assembly TerrariaAssembly
Definition: Logging.cs:326

◆ PrettifyStackTraceSources() [2/2]

static void Terraria.ModLoader.Logging.PrettifyStackTraceSources ( )
staticprivate

Definition at line 382 of file Logging.cs.

References Terraria.ModLoader.FrameworkVersion.Framework.

382  {
383  if (f_fileName == null)
384  return;
385 
386  if (FrameworkVersion.Framework == Framework.NetFramework)
387  new Hook(typeof(StackTrace).GetConstructor(new[] { typeof(Exception), typeof(bool) }), new hook_StackTrace(HookStackTraceEx));
388  else if (FrameworkVersion.Framework == Framework.Mono)
389  new Hook(typeof(Exception).FindMethod("GetStackTrace"), new hook_GetStackTrace(HookGetStackTrace));
390  }
static string HookGetStackTrace(orig_GetStackTrace orig, Exception self, bool fNeedFileInfo)
Definition: Logging.cs:344
delegate string hook_GetStackTrace(orig_GetStackTrace orig, Exception self, bool fNeedFileInfo)
delegate void hook_StackTrace(ctor_StackTrace orig, StackTrace self, Exception e, bool fNeedFileInfo)
static void HookStackTraceEx(ctor_StackTrace orig, StackTrace self, Exception e, bool fNeedFileInfo)
Definition: Logging.cs:331

◆ RollLogs()

static string Terraria.ModLoader.Logging.RollLogs ( string  baseName)
staticprivate

Definition at line 98 of file Logging.cs.

98  {
99  var pattern = new Regex($"{baseName}(\\d*)\\.log");
100  var existingLogs = Directory.GetFiles(LogDir).Where(s => pattern.IsMatch(Path.GetFileName(s))).ToList();
101 
102  if (!existingLogs.All(CanOpen)) {
103  int n = existingLogs.Select(s => {
104  var tok = pattern.Match(Path.GetFileName(s)).Groups[1].Value;
105  return tok.Length == 0 ? 1 : int.Parse(tok);
106  }).Max();
107  return $"{baseName}{n + 1}.log";
108  }
109 
110  foreach (var existingLog in existingLogs.OrderBy(File.GetCreationTime))
111  Archive(existingLog);
112 
114 
115  return $"{baseName}.log";
116  }
static void DeleteOldArchives()
Definition: Logging.cs:146
static readonly string LogDir
Definition: Logging.cs:28
static bool CanOpen(string fileName)
Definition: Logging.cs:118
static void Archive(string logPath)
Definition: Logging.cs:128

◆ SendRequest()

delegate EventHandler Terraria.ModLoader.Logging.SendRequest ( object  self,
HttpWebRequest  request 
)
private

◆ SendRequestHook()

delegate EventHandler Terraria.ModLoader.Logging.SendRequestHook ( SendRequest  orig,
object  self,
HttpWebRequest  request 
)
private

◆ SubmitRequest()

delegate bool Terraria.ModLoader.Logging.SubmitRequest ( object  self,
HttpWebRequest  request,
bool  forcedsubmit 
)
private

◆ SubmitRequestHook()

delegate bool Terraria.ModLoader.Logging.SubmitRequestHook ( SubmitRequest  orig,
object  self,
HttpWebRequest  request,
bool  forcedsubmit 
)
private

◆ WebOperation_ctor()

delegate void Terraria.ModLoader.Logging.WebOperation_ctor ( object  self,
HttpWebRequest  request,
object  writeBuffer,
bool  isNtlmChallenge,
CancellationToken  cancellationToken 
)
private

◆ WebOperation_ctorHook()

delegate void Terraria.ModLoader.Logging.WebOperation_ctorHook ( WebOperation_ctor  orig,
object  self,
HttpWebRequest  request,
object  writeBuffer,
bool  isNtlmChallenge,
CancellationToken  cancellationToken 
)
private

Member Data Documentation

◆ dropGenericTicks

readonly Regex Terraria.ModLoader.Logging.dropGenericTicks = new Regex(@"`\d+", RegexOptions.Compiled)
staticprivate

Definition at line 340 of file Logging.cs.

◆ dropOffset

readonly Regex Terraria.ModLoader.Logging.dropOffset = new Regex(@" \[.+?\](?![^:]+:-1)", RegexOptions.Compiled)
staticprivate

Definition at line 339 of file Logging.cs.

◆ ignoreContents

List<string> Terraria.ModLoader.Logging.ignoreContents
staticprivate
Initial value:
= new List<string> {
"System.Console.set_OutputEncoding",
"Terraria.ModLoader.ModCompile",
"Delegate.CreateDelegateNoSecurityCheck",
"MethodBase.GetMethodBody",
"Terraria.Net.Sockets.TcpSocket.Terraria.Net.Sockets.ISocket.AsyncSend",
"System.Diagnostics.Process.Kill",
}

Definition at line 229 of file Logging.cs.

◆ ignoreMessages

List<string> Terraria.ModLoader.Logging.ignoreMessages
staticprivate
Initial value:
= new List<string> {
"A blocking operation was interrupted by a call to WSACancelBlockingCall",
"The request was aborted: The request was canceled.",
"Object name: 'System.Net.Sockets.Socket'.",
"Object name: 'System.Net.Sockets.NetworkStream'",
"This operation cannot be performed on a completed asynchronous result object.",
"Object name: 'SslStream'.",
}

Definition at line 240 of file Logging.cs.

◆ ignoreSources

HashSet<string> Terraria.ModLoader.Logging.ignoreSources
staticprivate
Initial value:
= new HashSet<string> {
"MP3Sharp"
}

Definition at line 224 of file Logging.cs.

◆ LogDir

readonly string Terraria.ModLoader.Logging.LogDir = Path.Combine(Program.SavePath, "Logs")
static

Definition at line 28 of file Logging.cs.

Referenced by Terraria.ModLoader.ErrorLogger.ClearLogs().

◆ MAX_LOGS

const int Terraria.ModLoader.Logging.MAX_LOGS = 20
private

Definition at line 145 of file Logging.cs.

◆ pastExceptions

HashSet<string> Terraria.ModLoader.Logging.pastExceptions = new HashSet<string>()
staticprivate

Definition at line 221 of file Logging.cs.

◆ previousException

Exception Terraria.ModLoader.Logging.previousException
staticprivate

Definition at line 254 of file Logging.cs.

◆ statusRegex

Regex Terraria.ModLoader.Logging.statusRegex = new Regex(@"(.+?)[: \d]*%$")
staticprivate

Definition at line 300 of file Logging.cs.

◆ TerrariaAssembly

readonly Assembly Terraria.ModLoader.Logging.TerrariaAssembly = Assembly.GetExecutingAssembly()
staticprivate

Definition at line 326 of file Logging.cs.

◆ trimParamTypes

readonly Regex Terraria.ModLoader.Logging.trimParamTypes = new Regex(@"([([,] ?)(?:[\w.+]+[.+])", RegexOptions.Compiled)
staticprivate

Definition at line 338 of file Logging.cs.

Property Documentation

◆ LogPath

string Terraria.ModLoader.Logging.LogPath
staticgetprivate set

Definition at line 29 of file Logging.cs.