From c2385294eaf57312f233ad17220b0f31c5152b81 Mon Sep 17 00:00:00 2001 From: BlubbFish Date: Tue, 15 May 2018 18:49:03 +0000 Subject: [PATCH] Utils.csproj [NF] Programmlogger added (v1.1.0) [NF] Utils fixing tiny issues Zway-Bot.csproj [NF] changes Topics without beginning / [NF] Using programmlogger (v1.4.0) --- FileLogger.cs | 2 +- InIReader.cs | 2 +- ProgramLogger.cs | 163 +++++++++++++++++++++++++++++++++++++ Properties/AssemblyInfo.cs | 6 +- Utils.csproj | 1 + bin/Release/Utils.dll | Bin 25600 -> 29184 bytes 6 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 ProgramLogger.cs diff --git a/FileLogger.cs b/FileLogger.cs index 3d53fbe..0a50ffe 100644 --- a/FileLogger.cs +++ b/FileLogger.cs @@ -11,7 +11,7 @@ namespace BlubbFish.Utils { private static Dictionary instances = new Dictionary(); private static String logDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + Path.DirectorySeparatorChar; - private StreamWriter file; + private readonly StreamWriter file; private FileLogger(String filename, Boolean append) { filename = logDir + filename; diff --git a/InIReader.cs b/InIReader.cs index dfbe790..ec7ecc7 100644 --- a/InIReader.cs +++ b/InIReader.cs @@ -9,7 +9,7 @@ namespace BlubbFish.Utils { { private Dictionary> inifile; private FileSystemWatcher k; - private String filename; + private readonly String filename; private static List search_path = new List() { Directory.GetCurrentDirectory() }; diff --git a/ProgramLogger.cs b/ProgramLogger.cs new file mode 100644 index 0000000..ec7770c --- /dev/null +++ b/ProgramLogger.cs @@ -0,0 +1,163 @@ +using System; +using System.IO; +using System.Reflection; +using System.Security; +using System.Security.Permissions; +using System.Text; + +namespace BlubbFish.Utils { + public class ProgramLogger { + private FileWriter fw; + private ConsoleWriter stdout; + private ConsoleWriter errout; + private String loggerfile; + + public ProgramLogger() { + this.loggerfile = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "output.log"; + this.Init(this.loggerfile); + this.AttachToFw(); + this.SetOutputs(); + } + + private void SetOutputs() { + Console.SetOut(this.stdout); + Console.SetError(this.errout); + } + + private void Init(String file) { + if(!this.IsWritable(file)) { + Console.Error.WriteLine("Cannot write to " + file); + throw new ArgumentException("Cannot write to " + file); + } + this.fw = new FileWriter(file); + this.stdout = new ConsoleWriter(Console.Out, ConsoleWriterEventArgs.ConsoleType.Info); + this.errout = new ConsoleWriter(Console.Error, ConsoleWriterEventArgs.ConsoleType.Error); + } + + private Boolean IsWritable(String filename) { + FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, filename); + PermissionSet p = new PermissionSet(PermissionState.None); + p.AddPermission(writePermission); + if (!p.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet)) { + return false; + } + try { + using (FileStream fstream = new FileStream(filename, FileMode.Append)) + using (TextWriter writer = new StreamWriter(fstream)) { + writer.Write(""); + } + } catch (UnauthorizedAccessException) { + return false; + } + return true; + } + + public void SetPath(String file) { + if(file == null) { + return; + } + if (!this.IsWritable(file)) { + Console.Error.WriteLine("Cannot write to " + file); + throw new ArgumentException("Cannot write to " + file); + } + this.DisattachToFw(); + this.fw.Close(); + if(new FileInfo(this.loggerfile).Length > 0) { + File.Move(this.loggerfile, file); + } + this.loggerfile = file; + this.fw = new FileWriter(this.loggerfile); + this.AttachToFw(); + } + + private void DisattachToFw() { + this.stdout.WriteEvent -= this.fw.Write; + this.stdout.WriteLineEvent -= this.fw.WriteLine; + this.errout.WriteEvent -= this.fw.WriteLine; + this.errout.WriteLineEvent -= this.fw.WriteLine; + } + private void AttachToFw() { + this.stdout.WriteEvent += this.fw.Write; + this.stdout.WriteLineEvent += this.fw.WriteLine; + this.errout.WriteEvent += this.fw.WriteLine; + this.errout.WriteLineEvent += this.fw.WriteLine; + } + } + + internal class FileWriter : StreamWriter { + private Boolean newline = true; + public FileWriter(String path) : base(path) { + } + + public override Encoding Encoding { get { return Encoding.UTF8; } } + public override Boolean AutoFlush { get { return true; } set { base.AutoFlush = value; } } + + private void Write(String value, TextWriter origstream, ConsoleWriterEventArgs.ConsoleType type) { + String text = ""; + if (this.newline) { + text = "[" + DateTime.Now.ToString("o") + "]-" + type.ToString() + ": " + value; + this.newline = false; + } else { + text = value; + } + origstream.Write(text); + base.Write(text); + base.Flush(); + } + + private void WriteLine(String value, TextWriter origstream, ConsoleWriterEventArgs.ConsoleType type) { + String text = "[" + DateTime.Now.ToString("o") + "]-" + type.ToString() + ": " + value; + origstream.WriteLine(text); + base.WriteLine(text); + this.newline = true; + base.Flush(); + } + + internal void Write(Object sender, ConsoleWriterEventArgs e) { + this.Write(e.Value, e.Writer, e.StreamType); + } + + internal void WriteLine(Object sender, ConsoleWriterEventArgs e) { + this.WriteLine(e.Value, e.Writer, e.StreamType); + } + } + + internal class ConsoleWriterEventArgs : EventArgs { + public String Value { get; private set; } + public TextWriter Writer { get; private set; } + public ConsoleType StreamType { get; private set; } + + public enum ConsoleType { + Info, + Error + } + + public ConsoleWriterEventArgs(String value, TextWriter writer, ConsoleType type) { + this.Value = value; + this.Writer = writer; + this.StreamType = type; + } + } + + internal class ConsoleWriter : TextWriter { + private readonly TextWriter stream; + private readonly ConsoleWriterEventArgs.ConsoleType streamtype; + + public ConsoleWriter(TextWriter writer, ConsoleWriterEventArgs.ConsoleType type) { + this.stream = writer; + this.streamtype = type; + } + + public override Encoding Encoding { get { return Encoding.UTF8; } } + public override void Write(String value) { + this.WriteEvent?.Invoke(this, new ConsoleWriterEventArgs(value, this.stream, this.streamtype)); + base.Write(value); + } + public override void WriteLine(String value) { + this.WriteLineEvent?.Invoke(this, new ConsoleWriterEventArgs(value, this.stream, this.streamtype)); + base.WriteLine(value); + } + public event EventHandler WriteEvent; + public event EventHandler WriteLineEvent; + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index b0f4f6c..e8fc299 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Utils")] -[assembly: AssemblyCopyright("Copyright © 2014 - 07.05.2018")] +[assembly: AssemblyCopyright("Copyright © 2014 - 15.05.2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern // übernehmen, indem Sie "*" eingeben: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.7.0")] -[assembly: AssemblyFileVersion("1.0.7.0")] +[assembly: AssemblyVersion("1.1.0")] +[assembly: AssemblyFileVersion("1.1.0")] diff --git a/Utils.csproj b/Utils.csproj index 31fe9bd..83cfa61 100644 --- a/Utils.csproj +++ b/Utils.csproj @@ -50,6 +50,7 @@ + diff --git a/bin/Release/Utils.dll b/bin/Release/Utils.dll index c29cd0a08f67f676044b8ade6e243d1fee6ac6a2..30ab5f65166e16f62148074aaca34590ad84c251 100644 GIT binary patch literal 29184 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 delta 11443 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