Make Log thread-safe.

Since logging is exposed via static methods, it need to be thread-safe or multiple threads trying to log at the same time will cause bad things to happen.
This commit is contained in:
RoosterDragon
2016-01-04 19:27:48 +00:00
parent e9d76011c5
commit 081b40b14f
2 changed files with 41 additions and 34 deletions

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Network
{ {
try try
{ {
NatUtility.Logger = Log.Channels["server"].Writer; NatUtility.Logger = Log.Channel("server").Writer;
NatUtility.Verbose = Game.Settings.Server.VerboseNatDiscovery; NatUtility.Verbose = Game.Settings.Server.VerboseNatDiscovery;
NatUtility.DeviceFound += DeviceFound; NatUtility.DeviceFound += DeviceFound;
Game.Settings.Server.NatDeviceAvailable = false; Game.Settings.Server.NatDeviceAvailable = false;

View File

@@ -17,12 +17,12 @@ namespace OpenRA
public struct ChannelInfo public struct ChannelInfo
{ {
public string Filename; public string Filename;
public StreamWriter Writer; public TextWriter Writer;
} }
public static class Log public static class Log
{ {
public static readonly Dictionary<string, ChannelInfo> Channels = new Dictionary<string, ChannelInfo>(); static readonly Dictionary<string, ChannelInfo> Channels = new Dictionary<string, ChannelInfo>();
static IEnumerable<string> FilenamesForChannel(string channelName, string baseFilename) static IEnumerable<string> FilenamesForChannel(string channelName, string baseFilename)
{ {
@@ -33,56 +33,63 @@ namespace OpenRA
yield return Path.Combine(path, i > 0 ? "{0}.{1}".F(baseFilename, i) : baseFilename); yield return Path.Combine(path, i > 0 ? "{0}.{1}".F(baseFilename, i) : baseFilename);
} }
public static ChannelInfo Channel(string channelName)
{
ChannelInfo info;
lock (Channels)
if (!Channels.TryGetValue(channelName, out info))
throw new Exception("Tried logging to non-existent channel " + channelName);
return info;
}
public static void AddChannel(string channelName, string baseFilename) public static void AddChannel(string channelName, string baseFilename)
{ {
if (Channels.ContainsKey(channelName)) return; lock (Channels)
if (string.IsNullOrEmpty(baseFilename))
{ {
Channels.Add(channelName, new ChannelInfo()); if (Channels.ContainsKey(channelName)) return;
return;
}
foreach (var filename in FilenamesForChannel(channelName, baseFilename)) if (string.IsNullOrEmpty(baseFilename))
try
{ {
var writer = File.CreateText(filename); Channels.Add(channelName, new ChannelInfo());
writer.AutoFlush = true;
Channels.Add(channelName,
new ChannelInfo()
{
Filename = filename,
Writer = writer
});
return; return;
} }
catch (IOException) { }
foreach (var filename in FilenamesForChannel(channelName, baseFilename))
try
{
var writer = File.CreateText(filename);
writer.AutoFlush = true;
Channels.Add(channelName,
new ChannelInfo
{
Filename = filename,
Writer = TextWriter.Synchronized(writer)
});
return;
}
catch (IOException) { }
}
} }
public static void Write(string channel, string value) public static void Write(string channel, string value)
{ {
ChannelInfo info; var writer = Channel(channel).Writer;
if (!Channels.TryGetValue(channel, out info)) if (writer == null)
throw new Exception("Tried logging to non-existent channel " + channel);
if (info.Writer == null)
return; return;
info.Writer.WriteLine(value); writer.WriteLine(value);
} }
public static void Write(string channel, string format, params object[] args) public static void Write(string channel, string format, params object[] args)
{ {
ChannelInfo info; var writer = Channel(channel).Writer;
if (!Channels.TryGetValue(channel, out info)) if (writer == null)
throw new Exception("Tried logging to non-existent channel " + channel);
if (info.Writer == null)
return; return;
info.Writer.WriteLine(format, args); writer.WriteLine(format, args);
} }
} }
} }