├── .gitignore ├── README.md ├── license.md └── src ├── Log2Window.sln ├── Log2Window ├── AboutForm.Designer.cs ├── AboutForm.cs ├── AboutForm.resx ├── App.config ├── Config │ └── log4net.config ├── ICSharpCodeExtension │ └── Actions │ │ └── CaretActionsExtension.cs ├── Linq │ └── Linq.cs ├── Log │ ├── ILogManager.cs │ ├── ILogMessageNotifiable.cs │ ├── ILoggerView.cs │ ├── LogLevel.cs │ ├── LogLevelInfo.cs │ ├── LogLevels.cs │ ├── LogManager.cs │ ├── LogMessage.cs │ ├── LogMessageField.cs │ ├── LogMessageItem.cs │ ├── LogUtils.cs │ └── LoggerItem.cs ├── Log2Window.csproj ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── MyCategoryList.cs ├── MyList.cs ├── NListsMerger.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ ├── Settings.settings │ └── app.manifest ├── Receiver │ ├── BaseReceiver.cs │ ├── CsvFileReceiver.cs │ ├── DebugMonitor.cs │ ├── EventLogReceiver.cs │ ├── FileReceiver.cs │ ├── IReceiver.cs │ ├── MsmqReceiver.cs │ ├── ReceiverFactory.cs │ ├── ReceiverUtils.cs │ ├── RemotingReceiver.cs │ ├── SLPolicyServerReceiver.cs │ ├── TcpReceiver.cs │ ├── UdpReceiver.cs │ └── WinDebugReceiver.cs ├── Settings │ ├── FieldType.cs │ ├── LayoutSettings.cs │ ├── ReceiversForm.Designer.cs │ ├── ReceiversForm.cs │ ├── ReceiversForm.resx │ ├── SettingsForm.Designer.cs │ ├── SettingsForm.cs │ ├── SettingsForm.resx │ ├── SourceFileLocation.cs │ └── UserSettings.cs ├── UI │ ├── AutoWaitCursor.cs │ ├── ControlExtenders │ │ ├── DockExtender.cs │ │ ├── Floaty.cs │ │ └── Overlay.cs │ ├── FlickerFreeListView.cs │ ├── ToolStripControl.cs │ ├── TreeViewLoggerView.cs │ ├── TreeViewWithoutDoubleClick.cs │ └── WindowRestorer.cs ├── Utils.cs └── res │ ├── Excel.ico │ ├── Go16.png │ ├── Pause16.png │ ├── back16.png │ ├── backward16.png │ ├── burn16.png │ ├── cd16.png │ ├── close16.png │ ├── collapse_all.png │ ├── configure16.png │ ├── delete16.png │ ├── deletefile16.png │ ├── documentsorcopy16.png │ ├── eventLog.png │ ├── find16.png │ ├── forward16.png │ ├── gotoapp16.png │ ├── infoabout16.png │ ├── movefile16.png │ ├── next16.png │ ├── pin.png │ ├── receive.png │ ├── saveas16.png │ ├── unselect.png │ ├── window16.png │ ├── windowb.ico │ ├── zoomin16.png │ └── zoomout16.png ├── TestLog4net ├── App.config ├── Config │ └── log4net.config ├── MsmqAppender.cs ├── MyXmlLayoutSchemaLog4j.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── TcpAppender.cs └── TestLog4net.csproj ├── TestNLog ├── NLog.config ├── Program.cs ├── TestNLog.csproj └── app.config └── script_Publish.sh /.gitignore: -------------------------------------------------------------------------------- 1 | [Bb]in/ 2 | [Oo]bj/ 3 | [Ww]orking*/ 4 | Build/runbuild.txt 5 | Doc/doc.shfbproj_* 6 | TestResults/ 7 | AppPackages/ 8 | *.suo 9 | *.user 10 | *.userprefs 11 | _ReSharper.* 12 | *.ReSharper.user 13 | *.resharper.user 14 | project.lock.json 15 | *.xproj 16 | .vs/ 17 | *.props 18 | *.targets 19 | 20 | #NuGet 21 | packages 22 | !packages/repositories.config -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Log2Window 2 | Log2Window is a log message viewer for log4net, nlog, eventLog, log4j and log4cxx, which has strongly extreme stability and very good performance. It can process millions of log messages less than a second. 3 | -------------------------------------------------------------------------------- /license.md: -------------------------------------------------------------------------------- 1 | BSD Copyright (c) 2007 2 | Copyright Rémy Baudet, 3 | Copyright Alanthinker, 4 | All rights reserved 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 11 | 12 | Neither the name of Log2Window nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 15 | -------------------------------------------------------------------------------- /src/Log2Window.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestNLog", "TestNLog\TestNLog.csproj", "{7C4E8E11-81E3-4297-A4D9-6F6DB90C8EF7}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Log2Window", "Log2Window\Log2Window.csproj", "{EE81C506-55E4-417E-B1D6-09453F89C7CD}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestLog4net", "TestLog4net\TestLog4net.csproj", "{29A745D4-5A2F-4170-A0F1-54C77F151892}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | CodeAnalysisDebug|Any CPU = CodeAnalysisDebug|Any CPU 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {7C4E8E11-81E3-4297-A4D9-6F6DB90C8EF7}.CodeAnalysisDebug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {7C4E8E11-81E3-4297-A4D9-6F6DB90C8EF7}.CodeAnalysisDebug|Any CPU.Build.0 = Debug|Any CPU 21 | {7C4E8E11-81E3-4297-A4D9-6F6DB90C8EF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {7C4E8E11-81E3-4297-A4D9-6F6DB90C8EF7}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {EE81C506-55E4-417E-B1D6-09453F89C7CD}.CodeAnalysisDebug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {EE81C506-55E4-417E-B1D6-09453F89C7CD}.CodeAnalysisDebug|Any CPU.Build.0 = Debug|Any CPU 25 | {EE81C506-55E4-417E-B1D6-09453F89C7CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {EE81C506-55E4-417E-B1D6-09453F89C7CD}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {EE81C506-55E4-417E-B1D6-09453F89C7CD}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {EE81C506-55E4-417E-B1D6-09453F89C7CD}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {29A745D4-5A2F-4170-A0F1-54C77F151892}.CodeAnalysisDebug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {29A745D4-5A2F-4170-A0F1-54C77F151892}.CodeAnalysisDebug|Any CPU.Build.0 = Debug|Any CPU 31 | {29A745D4-5A2F-4170-A0F1-54C77F151892}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {29A745D4-5A2F-4170-A0F1-54C77F151892}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {29A745D4-5A2F-4170-A0F1-54C77F151892}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {29A745D4-5A2F-4170-A0F1-54C77F151892}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /src/Log2Window/AboutForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Log2Window 2 | { 3 | partial class AboutForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | protected override void Dispose(bool disposing) 14 | { 15 | if (disposing && (components != null)) 16 | { 17 | components.Dispose(); 18 | } 19 | base.Dispose(disposing); 20 | } 21 | 22 | #region Windows Form Designer generated code 23 | 24 | /// 25 | /// Required method for Designer support - do not modify 26 | /// the contents of this method with the code editor. 27 | /// 28 | private void InitializeComponent() 29 | { 30 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutForm)); 31 | this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); 32 | this.logoPictureBox = new System.Windows.Forms.PictureBox(); 33 | this.flowLayoutPanel3 = new System.Windows.Forms.FlowLayoutPanel(); 34 | this.labelProductName = new System.Windows.Forms.Label(); 35 | this.labelVersion = new System.Windows.Forms.Label(); 36 | this.labelCompileTime = new System.Windows.Forms.Label(); 37 | this.labelLink = new System.Windows.Forms.LinkLabel(); 38 | this.textBoxDescription = new System.Windows.Forms.TextBox(); 39 | this.okButton = new System.Windows.Forms.Button(); 40 | this.labelEmail = new System.Windows.Forms.Label(); 41 | this.flowLayoutPanel1.SuspendLayout(); 42 | ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); 43 | this.flowLayoutPanel3.SuspendLayout(); 44 | this.SuspendLayout(); 45 | // 46 | // flowLayoutPanel1 47 | // 48 | this.flowLayoutPanel1.Controls.Add(this.logoPictureBox); 49 | this.flowLayoutPanel1.Controls.Add(this.flowLayoutPanel3); 50 | this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; 51 | this.flowLayoutPanel1.Location = new System.Drawing.Point(9, 9); 52 | this.flowLayoutPanel1.Name = "flowLayoutPanel1"; 53 | this.flowLayoutPanel1.Size = new System.Drawing.Size(475, 448); 54 | this.flowLayoutPanel1.TabIndex = 1; 55 | // 56 | // logoPictureBox 57 | // 58 | this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); 59 | this.logoPictureBox.Location = new System.Drawing.Point(3, 3); 60 | this.logoPictureBox.Name = "logoPictureBox"; 61 | this.logoPictureBox.Size = new System.Drawing.Size(125, 271); 62 | this.logoPictureBox.TabIndex = 14; 63 | this.logoPictureBox.TabStop = false; 64 | // 65 | // flowLayoutPanel3 66 | // 67 | this.flowLayoutPanel3.Controls.Add(this.labelProductName); 68 | this.flowLayoutPanel3.Controls.Add(this.labelVersion); 69 | this.flowLayoutPanel3.Controls.Add(this.labelCompileTime); 70 | this.flowLayoutPanel3.Controls.Add(this.labelEmail); 71 | this.flowLayoutPanel3.Controls.Add(this.labelLink); 72 | this.flowLayoutPanel3.Controls.Add(this.textBoxDescription); 73 | this.flowLayoutPanel3.Controls.Add(this.okButton); 74 | this.flowLayoutPanel3.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; 75 | this.flowLayoutPanel3.Location = new System.Drawing.Point(134, 3); 76 | this.flowLayoutPanel3.Name = "flowLayoutPanel3"; 77 | this.flowLayoutPanel3.Size = new System.Drawing.Size(334, 442); 78 | this.flowLayoutPanel3.TabIndex = 1; 79 | // 80 | // labelProductName 81 | // 82 | this.labelProductName.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); 83 | this.labelProductName.ForeColor = System.Drawing.SystemColors.HotTrack; 84 | this.labelProductName.Location = new System.Drawing.Point(5, 5); 85 | this.labelProductName.Margin = new System.Windows.Forms.Padding(5); 86 | this.labelProductName.Name = "labelProductName"; 87 | this.labelProductName.Size = new System.Drawing.Size(200, 30); 88 | this.labelProductName.TabIndex = 25; 89 | this.labelProductName.Text = "Product Name"; 90 | this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 91 | // 92 | // labelVersion 93 | // 94 | this.labelVersion.AutoSize = true; 95 | this.labelVersion.Location = new System.Drawing.Point(5, 45); 96 | this.labelVersion.Margin = new System.Windows.Forms.Padding(5); 97 | this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17); 98 | this.labelVersion.Name = "labelVersion"; 99 | this.labelVersion.Size = new System.Drawing.Size(42, 13); 100 | this.labelVersion.TabIndex = 24; 101 | this.labelVersion.Text = "Version"; 102 | this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 103 | // 104 | // labelCompileTime 105 | // 106 | this.labelCompileTime.AutoSize = true; 107 | this.labelCompileTime.Location = new System.Drawing.Point(5, 68); 108 | this.labelCompileTime.Margin = new System.Windows.Forms.Padding(5); 109 | this.labelCompileTime.MaximumSize = new System.Drawing.Size(0, 17); 110 | this.labelCompileTime.Name = "labelCompileTime"; 111 | this.labelCompileTime.Size = new System.Drawing.Size(89, 13); 112 | this.labelCompileTime.TabIndex = 31; 113 | this.labelCompileTime.Text = "labelCompileTime"; 114 | this.labelCompileTime.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 115 | // 116 | // labelLink 117 | // 118 | this.labelLink.AutoSize = true; 119 | this.labelLink.Location = new System.Drawing.Point(5, 114); 120 | this.labelLink.Margin = new System.Windows.Forms.Padding(5); 121 | this.labelLink.MaximumSize = new System.Drawing.Size(0, 17); 122 | this.labelLink.Name = "labelLink"; 123 | this.labelLink.Size = new System.Drawing.Size(220, 13); 124 | this.labelLink.TabIndex = 28; 125 | this.labelLink.TabStop = true; 126 | this.labelLink.Text = "https://github.com/alanthinker/Log2Window"; 127 | this.labelLink.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 128 | this.labelLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.labelLink_LinkClicked); 129 | // 130 | // textBoxDescription 131 | // 132 | this.textBoxDescription.AcceptsReturn = true; 133 | this.textBoxDescription.Location = new System.Drawing.Point(5, 137); 134 | this.textBoxDescription.Margin = new System.Windows.Forms.Padding(5); 135 | this.textBoxDescription.Multiline = true; 136 | this.textBoxDescription.Name = "textBoxDescription"; 137 | this.textBoxDescription.ReadOnly = true; 138 | this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; 139 | this.textBoxDescription.Size = new System.Drawing.Size(318, 237); 140 | this.textBoxDescription.TabIndex = 29; 141 | this.textBoxDescription.TabStop = false; 142 | this.textBoxDescription.Text = "Description"; 143 | // 144 | // okButton 145 | // 146 | this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 147 | this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; 148 | this.okButton.Location = new System.Drawing.Point(243, 389); 149 | this.okButton.Margin = new System.Windows.Forms.Padding(10); 150 | this.okButton.Name = "okButton"; 151 | this.okButton.Size = new System.Drawing.Size(75, 20); 152 | this.okButton.TabIndex = 30; 153 | this.okButton.Text = "&OK"; 154 | // 155 | // labelEmail 156 | // 157 | this.labelEmail.AutoSize = true; 158 | this.labelEmail.Location = new System.Drawing.Point(5, 91); 159 | this.labelEmail.Margin = new System.Windows.Forms.Padding(5); 160 | this.labelEmail.MaximumSize = new System.Drawing.Size(0, 17); 161 | this.labelEmail.Name = "labelEmail"; 162 | this.labelEmail.Size = new System.Drawing.Size(111, 13); 163 | this.labelEmail.TabIndex = 32; 164 | this.labelEmail.Text = "alanthinker@126.com"; 165 | this.labelEmail.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 166 | // 167 | // AboutForm 168 | // 169 | this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); 170 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 171 | this.ClientSize = new System.Drawing.Size(493, 466); 172 | this.Controls.Add(this.flowLayoutPanel1); 173 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 174 | this.MaximizeBox = false; 175 | this.MinimizeBox = false; 176 | this.Name = "AboutForm"; 177 | this.Padding = new System.Windows.Forms.Padding(9); 178 | this.ShowIcon = false; 179 | this.ShowInTaskbar = false; 180 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 181 | this.Text = "About Log2Window"; 182 | this.flowLayoutPanel1.ResumeLayout(false); 183 | ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); 184 | this.flowLayoutPanel3.ResumeLayout(false); 185 | this.flowLayoutPanel3.PerformLayout(); 186 | this.ResumeLayout(false); 187 | 188 | } 189 | 190 | #endregion 191 | 192 | private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; 193 | private System.Windows.Forms.PictureBox logoPictureBox; 194 | private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel3; 195 | private System.Windows.Forms.Label labelProductName; 196 | private System.Windows.Forms.Label labelVersion; 197 | private System.Windows.Forms.LinkLabel labelLink; 198 | private System.Windows.Forms.TextBox textBoxDescription; 199 | private System.Windows.Forms.Button okButton; 200 | private System.Windows.Forms.Label labelCompileTime; 201 | private System.Windows.Forms.Label labelEmail; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/Log2Window/AboutForm.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/AboutForm.cs -------------------------------------------------------------------------------- /src/Log2Window/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Log2Window/Config/log4net.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/Log2Window/ICSharpCodeExtension/Actions/CaretActionsExtension.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.TextEditor; 2 | using ICSharpCode.TextEditor.Actions; 3 | 4 | namespace Log2Window.ICSharpCodeExtension.Actions 5 | { 6 | public class GotoLineNumber : AbstractEditAction 7 | { 8 | private readonly int _line; 9 | 10 | public GotoLineNumber(int line) 11 | { 12 | _line = line; 13 | } 14 | 15 | public override void Execute(TextArea textArea) 16 | { 17 | TextLocation position = textArea.Caret.Position; 18 | position.Line = _line; 19 | 20 | textArea.Caret.Position = position; 21 | textArea.SelectionManager.ClearSelection(); 22 | textArea.SetDesiredColumn(); 23 | 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Log2Window/Linq/Linq.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | #if !HASLINQ 4 | 5 | namespace System.Linq 6 | { 7 | /// 8 | /// This class replaces standars LINQ to Objects libraries (to be able to run on vanilla .NET 2.0 Framework) 9 | /// Methods are added on need-to-use basis 10 | /// 11 | internal static class Enumerable 12 | { 13 | public static IEnumerable Select(this IEnumerable source, Func selector) 14 | { 15 | if (source == null) 16 | throw new ArgumentNullException("source"); 17 | 18 | if (selector == null) 19 | throw new ArgumentNullException("selector"); 20 | 21 | foreach (var i in source) 22 | yield return selector(i); 23 | } 24 | 25 | public static int Min(this IEnumerable source) 26 | { 27 | if (source == null) 28 | throw new ArgumentNullException("source"); 29 | 30 | var min = 0; 31 | var hasElements = false; 32 | 33 | foreach (var i in source) 34 | { 35 | if (hasElements) 36 | { 37 | if (i < min) 38 | min = i; 39 | } 40 | else 41 | { 42 | min = i; 43 | hasElements = true; 44 | } 45 | } 46 | 47 | if (!hasElements) 48 | throw new ArgumentException("source"); 49 | 50 | return min; 51 | } 52 | 53 | public static int Max(this IEnumerable source) 54 | { 55 | if (source == null) 56 | throw new ArgumentNullException("source"); 57 | 58 | var max = 0; 59 | var hasElements = false; 60 | 61 | foreach (var i in source) 62 | { 63 | if (hasElements) 64 | { 65 | if (i > max) 66 | max = i; 67 | } 68 | else 69 | { 70 | max = i; 71 | hasElements = true; 72 | } 73 | } 74 | 75 | if (!hasElements) 76 | throw new ArgumentException("source"); 77 | 78 | return max; 79 | } 80 | 81 | public static int Min(this IEnumerable source, Func extractor) 82 | { 83 | return source.Select(extractor).Min(); 84 | } 85 | 86 | public static int Max(this IEnumerable source, Func extractor) 87 | { 88 | return source.Select(extractor).Max(); 89 | } 90 | } 91 | } 92 | 93 | namespace System 94 | { 95 | public delegate TResult Func(TParam param); 96 | } 97 | 98 | namespace System.Runtime.CompilerServices 99 | { 100 | public class ExtensionAttribute : Attribute { } 101 | } 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/Log2Window/Log/ILogManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Windows.Forms; 3 | 4 | 5 | namespace Log2Window.Log 6 | { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/Log2Window/Log/ILogMessageNotifiable.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace Log2Window.Log 3 | { 4 | /// 5 | /// This interface must be implemented to be notified when new log message arrives. 6 | /// 7 | public interface ILogMessageNotifiable 8 | { 9 | /// 10 | /// Call this method when a new log message is arrived. 11 | /// 12 | /// The message to log. 13 | void Notify(LogMessage logMsg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Log2Window/Log/ILoggerView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Drawing; 5 | 6 | namespace Log2Window.Log 7 | { 8 | /// 9 | /// Defines methods for allowing a LoggerItem to be shown in the UI. 10 | /// 11 | public interface ILoggerView 12 | { 13 | /// 14 | /// Clears this view and all child views. 15 | /// 16 | void Clear(); 17 | 18 | /// 19 | /// Adds the new logger view as a child of the current view and returns the new view. 20 | /// 21 | /// The text to initialize the view with. 22 | /// The logger that this instance is a view of. 23 | /// 24 | ILoggerView AddNew(string text, LoggerItem logger); 25 | 26 | /// 27 | /// Removes the logger view associated to the given text. 28 | /// 29 | void Remove(string text); 30 | 31 | void Sync(); 32 | 33 | 34 | /// 35 | /// Gets or sets the text of the view. The text is what is shown to the user. 36 | /// 37 | /// The text. 38 | string Text { get; set; } 39 | 40 | /// 41 | /// Gets or sets a value indicating whether this is enabled. 42 | /// 43 | /// true if enabled; otherwise, false. 44 | bool Enabled { get; set; } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Log2Window.Log 4 | { 5 | [Serializable] 6 | public enum LogLevel 7 | { 8 | None = -1, 9 | Trace = 0, 10 | Debug = 1, 11 | Info = 2, 12 | Warn = 3, 13 | Error = 4, 14 | Fatal = 5, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogLevelInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace Log2Window.Log 5 | { 6 | [Serializable] 7 | public class LogLevelInfo 8 | { 9 | public LogLevel Level; 10 | public string Name; 11 | public Color Color; 12 | public int Value; 13 | public int RangeMin; 14 | public int RangeMax; 15 | 16 | 17 | public LogLevelInfo(LogLevel level, Color color) 18 | { 19 | Level = level; 20 | Name = level.ToString(); 21 | Color = color; 22 | RangeMax = RangeMin = 0; 23 | } 24 | 25 | public LogLevelInfo(LogLevel level, string name, Color color, int value, int rangeMin, int rangeMax) 26 | { 27 | Level = level; 28 | Name = name; 29 | Color = color; 30 | Value = value; 31 | RangeMin = rangeMin; 32 | RangeMax = rangeMax; 33 | } 34 | 35 | public override bool Equals(object obj) 36 | { 37 | if (obj is LogLevelInfo) 38 | return ((obj as LogLevelInfo) == this); 39 | return base.Equals(obj); 40 | } 41 | 42 | public override int GetHashCode() 43 | { 44 | return Value.GetHashCode(); 45 | } 46 | 47 | public static bool operator ==(LogLevelInfo first, LogLevelInfo second) 48 | { 49 | if (((object)first == null) || ((object)second == null)) 50 | return (((object)first == null) && ((object)second == null)); 51 | return (first.Value == second.Value); 52 | } 53 | 54 | public static bool operator !=(LogLevelInfo first, LogLevelInfo second) 55 | { 56 | if (((object)first == null) || ((object)second == null)) 57 | return !(((object)first == null) && ((object)second == null)); 58 | return first.Value != second.Value; 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogLevels.cs: -------------------------------------------------------------------------------- 1 | using Log2Window.Settings; 2 | using System; 3 | using System.Drawing; 4 | 5 | namespace Log2Window.Log 6 | { 7 | public sealed class LogLevels 8 | { 9 | private static LogLevels _instance; 10 | 11 | public readonly LogLevelInfo InvalidLogLevel; 12 | public readonly LogLevelInfo[] LogLevelInfos; 13 | 14 | internal static LogLevels Instance 15 | { 16 | get 17 | { 18 | if (_instance == null) 19 | _instance = new LogLevels(); 20 | return _instance; 21 | } 22 | } 23 | 24 | internal LogLevelInfo this[int level] 25 | { 26 | get 27 | { 28 | if ((level < (int)LogLevel.Trace) || (level > (int)LogLevel.Fatal)) 29 | return InvalidLogLevel; 30 | return LogLevelInfos[level]; 31 | } 32 | } 33 | 34 | internal LogLevelInfo this[LogLevel logLevel] 35 | { 36 | get 37 | { 38 | int level = (int)logLevel; 39 | if ((level < (int)LogLevel.Trace) || (level > (int)LogLevel.Fatal)) 40 | return InvalidLogLevel; 41 | return LogLevelInfos[level]; 42 | } 43 | } 44 | 45 | internal LogLevelInfo this[string level] 46 | { 47 | get 48 | { 49 | foreach (LogLevelInfo info in LogLevelInfos) 50 | { 51 | if (info.Name.Equals(level, StringComparison.InvariantCultureIgnoreCase)) 52 | return info; 53 | } 54 | return InvalidLogLevel; 55 | } 56 | } 57 | 58 | private LogLevels() 59 | { 60 | InvalidLogLevel = new LogLevelInfo(LogLevel.None, Color.IndianRed); 61 | 62 | LogLevelInfos = new LogLevelInfo[] 63 | { 64 | new LogLevelInfo(LogLevel.Trace, "Trace", UserSettings.DefaultTraceLevelColor, 10000, 0, 10000), 65 | new LogLevelInfo(LogLevel.Debug, "Debug", UserSettings.DefaultDebugLevelColor, 30000, 10001, 30000), 66 | new LogLevelInfo(LogLevel.Info, "Info", UserSettings.DefaultInfoLevelColor, 40000, 30001, 40000), 67 | new LogLevelInfo(LogLevel.Warn, "Warn", UserSettings.DefaultWarnLevelColor, 60000, 40001, 60000), 68 | new LogLevelInfo(LogLevel.Error, "Error", UserSettings.DefaultErrorLevelColor, 70000, 60001, 70000), 69 | new LogLevelInfo(LogLevel.Fatal, "Fatal", UserSettings.DefaultFatalLevelColor, 110000, 70001, 110000), 70 | }; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Windows.Forms; 5 | 6 | 7 | namespace Log2Window.Log 8 | { 9 | public class LogManager 10 | { 11 | private static LogManager _instance; 12 | 13 | //_allLogMessageItems and _dataSource must use this locker. 14 | public readonly object dataLocker = new object(); 15 | //_allLogMessageItems may be reassigned, so cannot use as a locker. 16 | public MyCategoryList _allLogMessageItems = new MyCategoryList(new List { LogLevel.Fatal, LogLevel.Error, LogLevel.Warn, LogLevel.Info, LogLevel.Debug, LogLevel.Trace }); 17 | public MyList _dataSource = new MyList(); 18 | 19 | private LoggerItem _rootLoggerItem; 20 | private Dictionary _fullPathLoggers; 21 | public ListView _logListView; 22 | internal ulong manulSelectedArrivedId; 23 | 24 | public bool IsDelay { get; set; } 25 | 26 | private LogManager() 27 | { 28 | 29 | } 30 | 31 | internal static LogManager Instance 32 | { 33 | get 34 | { 35 | if (_instance == null) 36 | _instance = new LogManager(); 37 | return _instance; 38 | } 39 | } 40 | 41 | internal LoggerItem RootLoggerItem 42 | { 43 | get { return _rootLoggerItem; } 44 | set { _rootLoggerItem = value; } 45 | } 46 | 47 | public bool PauseRefreshNewMessages { get; set; } 48 | 49 | public void Initialize(ILoggerView loggerView, ListView logListView) 50 | { 51 | _logListView = logListView; 52 | // Root Logger 53 | _rootLoggerItem = LoggerItem.CreateRootLoggerItem("Root", loggerView, logListView); 54 | 55 | // Quick Access Logger Collection 56 | _fullPathLoggers = new Dictionary(); 57 | } 58 | 59 | public void ClearAll() 60 | { 61 | ClearLogMessages(); 62 | RootLoggerItem.ClearAll(); 63 | _fullPathLoggers.Clear(); 64 | } 65 | 66 | public void ClearLogMessages() 67 | { 68 | lock (dataLocker) 69 | { 70 | _allLogMessageItems.Clear(); 71 | _dataSource.Clear(); 72 | MainForm.Instance.ReBindListViewFromAllLogMessageItems(); 73 | 74 | GC.Collect(); 75 | } 76 | } 77 | 78 | public void DeactivateLogger() 79 | { 80 | RootLoggerItem.Enabled = false; 81 | } 82 | 83 | public void ProcessLogMessage(LogMessage logMsg) 84 | { 85 | // Check 1st in the global LoggerPath/Logger dictionary 86 | LoggerItem logger; 87 | logMsg.CheckNull(); 88 | 89 | // Search by thread need compare ThreadName. So need trim. 90 | logMsg.ThreadName = logMsg.ThreadName?.Trim(); 91 | 92 | if (!_fullPathLoggers.TryGetValue(logMsg.LoggerName, out logger)) 93 | { 94 | // Not found, create one 95 | logger = RootLoggerItem.GetOrCreateLogger(logMsg.LoggerName); 96 | } 97 | if (logger == null) 98 | throw new Exception("No Logger for this Log Message."); 99 | 100 | var item = logger.AddLogMessage(logMsg); 101 | 102 | lock (LogManager.Instance.dataLocker) 103 | { 104 | _allLogMessageItems.Enqueue(item, item.Message.Level.Level); 105 | if (item.Enabled && !LogManager.Instance.PauseRefreshNewMessages) 106 | { 107 | _dataSource.Enqueue(item); 108 | } 109 | 110 | // 只在 TryEnsureVisibleForSuitableItems 函数中调用 DequeueMoreThanMaxCount, 防止新增消息的时候, 影响listview的index指向的实际行. 111 | //DequeueMoreThanMaxCount(); 112 | } 113 | 114 | } 115 | 116 | public long DequeueMoreThanMaxCount() 117 | { 118 | long removedCount=0; 119 | var maxCount = Settings.UserSettings.Instance.MessageCycleCountForEachLevel; 120 | if (maxCount > 0) 121 | { 122 | removedCount = _allLogMessageItems.DequeueSmart(maxCount); 123 | if (removedCount > 0) 124 | { 125 | if (!LogManager.Instance.PauseRefreshNewMessages 126 | ) 127 | { 128 | MainForm.Instance.ReBindListViewFromAllLogMessageItems(false); 129 | } 130 | } 131 | } 132 | GC.Collect(); 133 | return removedCount; 134 | } 135 | 136 | public void allLogMessageItems_to_dataSource() 137 | { 138 | this._dataSource.Clear(); 139 | var temp = new MyCategoryList(new List { LogLevel.Fatal, LogLevel.Error, LogLevel.Warn, LogLevel.Info, LogLevel.Debug, LogLevel.Trace }); 140 | foreach (var item in this._allLogMessageItems) 141 | { 142 | item.Enabled = item.Parent.IsItemToBeEnabled(item); 143 | if (item.Enabled) 144 | { 145 | temp.Enqueue(item, item.Message.Level.Level); 146 | } 147 | } 148 | 149 | 150 | var listList = temp.ToListList(); 151 | var t0 = DateTime.Now; 152 | this._dataSource = new NListsMerger().MergeNLists(listList); 153 | var t1 = DateTime.Now; 154 | Trace.WriteLine("ts=" + (t1 - t0)); 155 | } 156 | 157 | public void SearchByTextAndThread(string text,string thread) 158 | { 159 | _rootLoggerItem.SearchByTextAndThread(text, thread); 160 | } 161 | 162 | 163 | public void UpdateLogLevel() 164 | { 165 | if (RootLoggerItem == null) 166 | return; 167 | 168 | RootLoggerItem.UpdateLogLevel(); 169 | } 170 | 171 | public void SetRootLoggerName(string name) 172 | { 173 | RootLoggerItem.Name = name; 174 | } 175 | 176 | internal bool inSetSelectedIndicesByCode; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Windows.Forms; 5 | using Log2Window.Settings; 6 | using System.Diagnostics; 7 | 8 | namespace Log2Window.Log 9 | { 10 | public class LogMessage 11 | { 12 | /// 13 | /// The Line Number of the Log Message 14 | /// 15 | public ulong SequenceNr; 16 | 17 | /// 18 | /// Logger Name. 19 | /// 20 | public string LoggerName; 21 | 22 | /// 23 | /// Root Logger Name. 24 | /// 25 | public string RootLoggerName; 26 | 27 | /// 28 | /// Log Level. 29 | /// 30 | public LogLevelInfo Level; 31 | 32 | /// 33 | /// Log Message. 34 | /// 35 | public string Message; 36 | 37 | /// 38 | /// Thread Name. 39 | /// 40 | public string ThreadName; 41 | 42 | /// 43 | /// Time Stamp. 44 | /// 45 | public DateTime TimeStamp; 46 | 47 | /// 48 | /// Properties collection. 49 | /// 50 | public Dictionary Properties = new Dictionary(); 51 | 52 | /// 53 | /// An exception message to associate to this message. 54 | /// 55 | public string ExceptionString; 56 | 57 | /// 58 | /// The CallSite Class 59 | /// 60 | public string CallSiteClass; 61 | 62 | 63 | /// 64 | /// The CallSite Method in which the Log is made 65 | /// 66 | public string CallSiteMethod; 67 | 68 | /// 69 | /// The Name of the Source File 70 | /// 71 | public string SourceFileName; 72 | 73 | /// 74 | /// The Line of the Source File 75 | /// 76 | public uint? SourceFileLineNr; 77 | 78 | //Only allowed set ArrivedId in constructor. 79 | public readonly ulong ArrivedId; 80 | 81 | public LogMessage() 82 | { 83 | ArrivedId = IdCreator.GetNextId(); 84 | } 85 | 86 | public void CheckNull() 87 | { 88 | if (string.IsNullOrEmpty(LoggerName)) 89 | LoggerName = "Unknown"; 90 | if (string.IsNullOrEmpty(RootLoggerName)) 91 | RootLoggerName = "Unknown"; 92 | if (string.IsNullOrEmpty(Message)) 93 | Message = "Unknown"; 94 | if (string.IsNullOrEmpty(ThreadName)) 95 | ThreadName = string.Empty; 96 | if (string.IsNullOrEmpty(ExceptionString)) 97 | ExceptionString = string.Empty; 98 | if (string.IsNullOrEmpty(ExceptionString)) 99 | ExceptionString = string.Empty; 100 | if (string.IsNullOrEmpty(CallSiteClass)) 101 | CallSiteClass = string.Empty; 102 | if (string.IsNullOrEmpty(CallSiteMethod)) 103 | CallSiteMethod = string.Empty; 104 | if (string.IsNullOrEmpty(SourceFileName)) 105 | SourceFileName = string.Empty; 106 | if (Level == null) 107 | Level = LogLevels.Instance[(LogLevel.Error)]; 108 | } 109 | 110 | public override string ToString() 111 | { 112 | var sb = new StringBuilder(); 113 | foreach (var fieldType in UserSettings.Instance.ColumnConfiguration) 114 | { 115 | sb.Append(GetInformation(fieldType)); 116 | sb.Append("\t"); 117 | } 118 | return sb.ToString(); 119 | } 120 | 121 | private string GetInformation(FieldType fieldType) 122 | { 123 | string result = string.Empty; 124 | switch (fieldType.Field) 125 | { 126 | case LogMessageField.SequenceNr: 127 | result = SequenceNr.ToString(); 128 | break; 129 | case LogMessageField.ArrivedId: 130 | result = ArrivedId.ToString(); 131 | break; 132 | case LogMessageField.LoggerName: 133 | result = LoggerName; 134 | break; 135 | case LogMessageField.RootLoggerName: 136 | result = RootLoggerName; 137 | break; 138 | case LogMessageField.Level: 139 | result = Level.Level.ToString(); 140 | break; 141 | case LogMessageField.Message: 142 | result = Message; 143 | break; 144 | case LogMessageField.ThreadName: 145 | result = ThreadName; 146 | break; 147 | case LogMessageField.TimeStamp: 148 | result = TimeStamp.ToString(UserSettings.Instance.TimeStampFormatString); 149 | break; 150 | case LogMessageField.Exception: 151 | result = ExceptionString; 152 | break; 153 | case LogMessageField.CallSiteClass: 154 | result = CallSiteClass; 155 | break; 156 | case LogMessageField.CallSiteMethod: 157 | result = CallSiteMethod; 158 | break; 159 | case LogMessageField.SourceFileName: 160 | result = SourceFileName; 161 | break; 162 | case LogMessageField.SourceFileLineNr: 163 | result = SourceFileLineNr.ToString(); 164 | break; 165 | case LogMessageField.Properties: 166 | { 167 | StringBuilder sb = new StringBuilder(); 168 | 169 | foreach (var property in Properties) 170 | { 171 | sb.Append(property.Key + ": "); 172 | sb.AppendLine(property.Value); 173 | } 174 | result = sb.ToString(); 175 | } 176 | 177 | break; 178 | } 179 | return result; 180 | } 181 | 182 | internal void GetMessageDetails(RichTextBox logDetailTextBox, RichTextBox tbMessage) 183 | { 184 | logDetailTextBox.Clear(); 185 | foreach (var fieldType in UserSettings.Instance.MessageDetailConfiguration) 186 | { 187 | //var info = GetInformation(fieldType).Replace(@"\", @"\\").Replace("{", @"\{").Replace("}", @"\}"); 188 | //sb.Append(@"\b " + fieldType.Field + @": \b0 "); 189 | //if (info.Length > 40) 190 | // sb.Append(@" \line "); 191 | //sb.Append(info + @" \line "); 192 | 193 | var info = GetInformation(fieldType); 194 | 195 | if (fieldType.Field == LogMessageField.Message) 196 | { 197 | //Utils.log.Debug(info); 198 | tbMessage.Text = info; 199 | 200 | if (!string.IsNullOrEmpty(this.ExceptionString)) 201 | { 202 | tbMessage.Text += "\n\n" + this.ExceptionString; 203 | } 204 | } 205 | else 206 | { 207 | var oldColor = logDetailTextBox.SelectionColor; 208 | logDetailTextBox.SelectionColor = System.Drawing.Color.Brown; 209 | logDetailTextBox.SelectionFont = new System.Drawing.Font(logDetailTextBox.SelectionFont, System.Drawing.FontStyle.Bold); 210 | logDetailTextBox.AppendText(fieldType.Field + ": "); 211 | logDetailTextBox.SelectionFont = new System.Drawing.Font(logDetailTextBox.SelectionFont, System.Drawing.FontStyle.Regular); 212 | logDetailTextBox.SelectionColor = oldColor; 213 | if (info.Length > 40) 214 | logDetailTextBox.AppendText("\n"); 215 | logDetailTextBox.AppendText(info + "\n"); 216 | } 217 | } 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogMessageField.cs: -------------------------------------------------------------------------------- 1 | namespace Log2Window.Log 2 | { 3 | public enum LogMessageField 4 | { 5 | ArrivedId, 6 | SequenceNr, 7 | RootLoggerName, 8 | LoggerName, 9 | Level, 10 | Message, 11 | ThreadName, 12 | TimeStamp, 13 | Exception, 14 | CallSiteClass, 15 | CallSiteMethod, 16 | SourceFileName, 17 | SourceFileLineNr, 18 | Properties 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogMessageItem.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Log2Window.Settings; 3 | using System; 4 | using System.Drawing; 5 | using System.Windows.Forms; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | namespace Log2Window.Log 11 | { 12 | public static class IdCreator 13 | { 14 | private static readonly object idLocker = new object(); 15 | 16 | private static ulong id = 1; 17 | public static ulong GetNextId() 18 | { 19 | lock (idLocker) 20 | { 21 | return id++; 22 | } 23 | } 24 | } 25 | 26 | /// 27 | /// Describes a Log Message. 28 | /// TODO: Make it disposable to dereference Item? 29 | /// 30 | public class LogMessageItem : IComparable 31 | { 32 | /// 33 | /// Logger Item Parent. 34 | /// 35 | public LoggerItem Parent; 36 | 37 | ///// 38 | ///// The item before this one, allow to retrieve the order of arrival (time is not reliable here). 39 | ///// The previous item is not necessary a sibling in the logger tree, only in the message list view. 40 | ///// 41 | //public LogMessageItem Previous; 42 | 43 | // public long ArrivedId; 44 | 45 | ///// 46 | ///// The associated List View Item. 47 | ///// 48 | //public ListViewItem Item; 49 | 50 | /// 51 | /// Log Message. 52 | /// 53 | public LogMessage Message; 54 | 55 | /// 56 | /// Indicates if this Log Message Item is enable. 57 | /// When disabled the List View Item is not in the Log List View. 58 | /// 59 | public bool Enabled = true; 60 | 61 | public LogMessageItem(LoggerItem parent, LogMessage logMsg) 62 | { 63 | Parent = parent; 64 | Message = logMsg; 65 | } 66 | 67 | public static ListViewItem CreateListViewItem(LogMessage logMsg) 68 | { 69 | Utils.log.Debug("CreateListViewItem " + logMsg.ArrivedId); 70 | // Create List View Item 71 | var items = new ListViewItem.ListViewSubItem[UserSettings.Instance.ColumnConfiguration.Length]; 72 | string toolTip = string.Empty; 73 | 74 | //Add all the Standard Fields to the ListViewItem 75 | for (int i = 0; i < UserSettings.Instance.ColumnConfiguration.Length; i++) 76 | { 77 | items[i] = new ListViewItem.ListViewSubItem(); 78 | 79 | switch (UserSettings.Instance.ColumnConfiguration[i].Field) 80 | { 81 | case LogMessageField.SequenceNr: 82 | items[i].Text = logMsg.SequenceNr.ToString(); 83 | break; 84 | case LogMessageField.ArrivedId: 85 | items[i].Text = logMsg.ArrivedId.ToString(); 86 | break; 87 | case LogMessageField.LoggerName: 88 | items[i].Text = logMsg.LoggerName; 89 | break; 90 | case LogMessageField.RootLoggerName: 91 | items[i].Text = logMsg.RootLoggerName; 92 | break; 93 | case LogMessageField.Level: 94 | items[i].Text = logMsg.Level.Name; 95 | break; 96 | case LogMessageField.Message: 97 | StringBuilder sbMsg = new StringBuilder(logMsg.Message); 98 | if (!string.IsNullOrEmpty(logMsg.ExceptionString)) 99 | { 100 | sbMsg.Append(" " + logMsg.ExceptionString); 101 | } 102 | sbMsg.Replace("\r\n", " "); 103 | sbMsg.Replace("\n", " "); 104 | var msg = sbMsg.ToString(); 105 | items[i].Text = msg; 106 | toolTip = msg; 107 | break; 108 | case LogMessageField.ThreadName: 109 | items[i].Text = logMsg.ThreadName; 110 | break; 111 | case LogMessageField.TimeStamp: 112 | items[i].Text = logMsg.TimeStamp.ToString(UserSettings.Instance.TimeStampFormatString); 113 | break; 114 | case LogMessageField.Exception: 115 | string exception = logMsg.ExceptionString.Replace("\r\n", " "); 116 | exception = exception.Replace("\n", " "); 117 | items[i].Text = exception; 118 | break; 119 | case LogMessageField.CallSiteClass: 120 | items[i].Text = logMsg.CallSiteClass; 121 | break; 122 | case LogMessageField.CallSiteMethod: 123 | items[i].Text = logMsg.CallSiteMethod; 124 | break; 125 | case LogMessageField.SourceFileName: 126 | items[i].Text = logMsg.SourceFileName; 127 | break; 128 | case LogMessageField.SourceFileLineNr: 129 | items[i].Text = logMsg.SourceFileLineNr.ToString(); 130 | break; 131 | case LogMessageField.Properties: 132 | break; 133 | } 134 | } 135 | 136 | //Add all the Properties in the Message to the ListViewItem 137 | foreach (var property in logMsg.Properties) 138 | { 139 | string propertyKey = property.Key; 140 | if (UserSettings.Instance.ColumnProperties.ContainsKey(propertyKey)) 141 | { 142 | int propertyColumnNumber = UserSettings.Instance.ColumnProperties[propertyKey]; 143 | if (propertyColumnNumber < items.Length) 144 | { 145 | items[propertyColumnNumber].Text = property.Value; 146 | } 147 | } 148 | } 149 | 150 | var Item = new ListViewItem(items, 0) { ToolTipText = toolTip, ForeColor = logMsg.Level.Color };//, Tag = this }; 151 | return Item; 152 | } 153 | 154 | internal bool IsLevelInRange() 155 | { 156 | return (Message.Level.RangeMax >= UserSettings.Instance.LogLevelInfo.RangeMax); 157 | } 158 | 159 | //internal void HighlightSearchedText(bool hasText, string str) 160 | //{ 161 | // if (hasText && HasSearchedText(str)) 162 | // Item.BackColor = Color.LightYellow; 163 | // else 164 | // Item.BackColor = Color.Transparent; 165 | //} 166 | 167 | internal bool HasSearchedText(string str) 168 | { 169 | return (Message.Message.IndexOf(str, StringComparison.InvariantCultureIgnoreCase) >= 0); 170 | } 171 | 172 | internal bool IsThreadMatch(string[] threads) 173 | { 174 | return threads.Contains(Message.ThreadName); 175 | } 176 | 177 | internal void GetMessageDetails(RichTextBox logDetailTextBox, RichTextBox tbMessage) 178 | { 179 | Message.GetMessageDetails(logDetailTextBox, tbMessage); 180 | } 181 | 182 | public int CompareTo(LogMessageItem other) 183 | { 184 | return this.Message.ArrivedId.CompareTo(other.Message.ArrivedId); 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/Log2Window/Log/LogUtils.cs: -------------------------------------------------------------------------------- 1 | namespace Log2Window.Log 2 | { 3 | public static class LogUtils 4 | { 5 | public static bool IsInRange(int val, int min, int max) 6 | { 7 | return (val >= min) && (val <= max); 8 | } 9 | 10 | public static LogLevelInfo GetLogLevelInfo(int level) 11 | { 12 | foreach (LogLevelInfo info in LogLevels.Instance.LogLevelInfos) 13 | { 14 | if (IsInRange(level, info.RangeMin, info.RangeMax)) 15 | return info; 16 | } 17 | 18 | return LogLevels.Instance.InvalidLogLevel; 19 | } 20 | 21 | public static LogLevelInfo GetLogLevelInfo(LogLevel level) 22 | { 23 | foreach (LogLevelInfo info in LogLevels.Instance.LogLevelInfos) 24 | { 25 | if (level == info.Level) 26 | return info; 27 | } 28 | 29 | return LogLevels.Instance.InvalidLogLevel; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Log2Window/MainForm.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/MainForm.cs -------------------------------------------------------------------------------- /src/Log2Window/MyCategoryList.cs: -------------------------------------------------------------------------------- 1 | using ICSharpCode.TextEditor.Actions; 2 | using Log2Window.Log; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Log2Window 10 | { 11 | public class MyCategoryList 12 | { 13 | Dictionary> _categories = new Dictionary>(); 14 | 15 | public MyCategoryList(List cats) 16 | { 17 | foreach (var cat in cats) 18 | { 19 | if (!_categories.ContainsKey(cat)) 20 | { 21 | _categories.Add(cat, new MyList()); 22 | } 23 | } 24 | } 25 | 26 | public long AllItemsCount 27 | { 28 | get 29 | { 30 | long count = 0; 31 | foreach (var pair in _categories) 32 | { 33 | count += pair.Value.Count; 34 | } 35 | return count; 36 | } 37 | } 38 | 39 | public void Enqueue(T item, CAT cat) 40 | { 41 | _categories[cat].Enqueue(item); 42 | } 43 | 44 | public void Clear() 45 | { 46 | foreach (var pair in _categories) 47 | { 48 | pair.Value.Clear(); 49 | } 50 | } 51 | 52 | // 为了防止反复多次调用 DequeueSmart, 只要在每个cat的元素数量超过 110%的 catMaxItemsCount 的时候, 才执行 Dequeue, 53 | // 一旦执行, 最终元素数量被减小到 100% 以内. 54 | public long DequeueSmart(long catMaxItemsCount) 55 | { 56 | var max_110_percent = catMaxItemsCount * 1.1; 57 | 58 | long dequeuedCount = 0; 59 | foreach (var pair in _categories) 60 | { 61 | if (pair.Value.Count > max_110_percent) 62 | { 63 | while (pair.Value.Count > catMaxItemsCount) 64 | { 65 | pair.Value.Dequeue(); 66 | dequeuedCount++; 67 | } 68 | } 69 | } 70 | 71 | return dequeuedCount; 72 | } 73 | 74 | public IEnumerator GetEnumerator() 75 | { 76 | foreach (var cat in _categories) 77 | { 78 | foreach (var item in cat.Value) 79 | { 80 | yield return item; 81 | } 82 | } 83 | } 84 | 85 | public List> ToListList() 86 | { 87 | List> list = new List>(); 88 | foreach (var cat in _categories) 89 | { 90 | list.Add(cat.Value); 91 | } 92 | return list; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Log2Window/MyList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Log2Window 7 | { 8 | /// 9 | /// A collection which can support index, Enqueue, Dequeue, Peek, GetEnumerator with very good performance. 10 | /// Have both advantage of Queue and List. 11 | /// 12 | /// 13 | public class MyList 14 | { 15 | private List list = new List(); 16 | private int startIndex = 0; 17 | private int endIndexAddOne = 0;//not include; 18 | 19 | private int resetCount = 1000; 20 | public long StateId { get; private set; } 21 | 22 | public T this[int index] 23 | { 24 | get 25 | { 26 | return list[index + startIndex]; 27 | } 28 | } 29 | 30 | public int Count 31 | { 32 | get 33 | { 34 | return endIndexAddOne - startIndex; 35 | } 36 | } 37 | 38 | public void Enqueue(T item) 39 | { 40 | StateId++; 41 | list.Add(item); 42 | endIndexAddOne++; 43 | 44 | if (startIndex > resetCount && startIndex > endIndexAddOne / 2) 45 | { 46 | var newlist = new List(this.Count); 47 | foreach (var temp in this) 48 | { 49 | newlist.Add(temp); 50 | } 51 | list.Clear(); 52 | list = newlist; 53 | startIndex = 0; 54 | endIndexAddOne = list.Count; 55 | } 56 | } 57 | 58 | public void Clear() 59 | { 60 | StateId++; 61 | list.Clear(); 62 | endIndexAddOne = 0; 63 | startIndex = 0; 64 | } 65 | 66 | public IEnumerator GetEnumerator() 67 | { 68 | for (int i = startIndex; i < endIndexAddOne; i++) 69 | { 70 | yield return list[i]; 71 | } 72 | } 73 | 74 | public T Peek() 75 | { 76 | return list[startIndex]; 77 | } 78 | 79 | public T Dequeue() 80 | { 81 | StateId++; 82 | var item = this.Peek(); 83 | startIndex++; 84 | return item; 85 | } 86 | 87 | public void Sort() 88 | { 89 | this.list.Sort(startIndex, endIndexAddOne - startIndex, Comparer.Default); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Log2Window/NListsMerger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Log2Window 8 | { 9 | class NListsMerger where T : IComparable 10 | { 11 | private MyList Merge2Lists(MyList arr1, MyList arr2) 12 | { 13 | int len1 = arr1.Count; 14 | int len2 = arr2.Count; 15 | 16 | // 定义结果数组 17 | var merged = new MyList(); 18 | 19 | // 定义索引位置 20 | int loc1, loc2; 21 | loc1 = loc2 = 0; 22 | 23 | // 遍历两个数组 24 | while (loc1 < len1 && loc2 < len2) 25 | { 26 | if (arr1[loc1].CompareTo(arr2[loc2]) < 0) 27 | { 28 | merged.Enqueue(arr1[loc1++]); 29 | } 30 | else 31 | { 32 | merged.Enqueue(arr2[loc2++]); 33 | } 34 | } 35 | 36 | // 拷贝较长数组余下的元素 37 | while (loc1 < len1) 38 | { 39 | merged.Enqueue(arr1[loc1++]); 40 | } 41 | 42 | while (loc2 < len2) 43 | { 44 | merged.Enqueue(arr2[loc2++]); 45 | } 46 | 47 | return merged; 48 | } 49 | 50 | public MyList MergeNLists(List> lists) 51 | { 52 | if (lists.Count == 0) 53 | { 54 | return null; 55 | } 56 | return Merge(lists, 0, lists.Count - 1); 57 | } 58 | 59 | private MyList Merge(List> lists, int lo, int hi) 60 | { 61 | if (lo == hi) 62 | { 63 | return lists[lo]; 64 | } 65 | int mid = lo + (hi - lo) / 2; 66 | MyList l1 = Merge(lists, lo, mid); 67 | MyList l2 = Merge(lists, mid + 1, hi); 68 | return Merge2Lists(l1, l2); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Log2Window/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Windows.Forms; 6 | 7 | 8 | namespace Log2Window 9 | { 10 | static class Program 11 | { 12 | /// 13 | /// The main entry point for the application. 14 | /// 15 | [STAThread] 16 | static void Main(string[] args) 17 | { 18 | if (args.Length > 0) 19 | { 20 | if (args[0].ToLower() == "ClearEventLog".ToLower()) 21 | { 22 | MainForm.ClearEventLog(args[1]); 23 | return; 24 | } 25 | } 26 | 27 | log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo("Config/log4net.config")); 28 | Application.ThreadException += Application_ThreadException; 29 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 30 | 31 | 32 | Application.EnableVisualStyles(); 33 | Application.SetCompatibleTextRenderingDefault(false); 34 | Application.Run(new MainForm()); 35 | } 36 | 37 | private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) 38 | { 39 | Utils.log.Error("Application_ThreadException", e.Exception); 40 | 41 | //MessageBox.Show(e.Exception.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 42 | } 43 | 44 | private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) 45 | { 46 | Utils.log.Error("CurrentDomain_UnhandledException", e.ExceptionObject as Exception); 47 | //MessageBox.Show(e.ExceptionObject.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/Log2Window/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Log2Window")] 8 | [assembly: AssemblyDescription(@"Log2Window is a log message viewer for log4net, nlog, eventLog, log4j and log4cxx, which has strongly extreme stability and very good performance. It can process millions of log messages less than a second.")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("AlanThinker")] 11 | [assembly: AssemblyProduct("Log2Window")] 12 | [assembly: AssemblyCopyright("AlanThinker 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("2881D007-28BD-4907-B4F4-09B627CE8FE4")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | //自2000年1月1日以来的天数作为内部版本号,以及自午夜以来的秒数除以2作为修订版, 注意, 必须给星号留够后面2位 32 | [assembly: AssemblyVersion("2.2.*")] 33 | 34 | -------------------------------------------------------------------------------- /src/Log2Window/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Log2Window.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Log2Window/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Log2Window/Properties/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 8 | 16 | 17 | 18 | true 19 | PerMonitorV2 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/BaseReceiver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | using Log2Window.Log; 5 | using System.Text; 6 | using System.Windows.Forms; 7 | 8 | namespace Log2Window.Receiver 9 | { 10 | [Serializable] 11 | public abstract class BaseReceiver : MarshalByRefObject, IReceiver, ICloneable 12 | { 13 | [NonSerialized] 14 | protected ILogMessageNotifiable Notifiable; 15 | 16 | [NonSerialized] 17 | private string _displayName; 18 | 19 | 20 | #region IReceiver Members 21 | 22 | public abstract string SampleClientConfig { get; } 23 | 24 | [Browsable(false)] 25 | public string DisplayName 26 | { 27 | get { return _displayName; } 28 | protected set { _displayName = value; } 29 | } 30 | 31 | string m_TextEncoding = "utf-8"; 32 | 33 | [Category("Configuration")] 34 | [DisplayName("Encoding")] 35 | [DefaultValue("utf-8")] 36 | public virtual string TextEncoding 37 | { 38 | get { return m_TextEncoding; } 39 | set 40 | { 41 | try 42 | { 43 | var tempEncoding= Encoding.GetEncoding(value); 44 | this.m_TextEncoding = value; 45 | this.encodingObject = tempEncoding; 46 | } 47 | catch (Exception ex) 48 | { 49 | MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 50 | } 51 | } 52 | } 53 | 54 | private Encoding encodingObject=Encoding.UTF8; 55 | protected Encoding EncodingObject 56 | { 57 | get 58 | { 59 | return encodingObject; 60 | } 61 | } 62 | 63 | 64 | public abstract void Initialize(); 65 | public abstract void Terminate(); 66 | 67 | public void Attach(ILogMessageNotifiable notifiable) 68 | { 69 | Notifiable = notifiable; 70 | } 71 | 72 | public virtual void Stop() 73 | { 74 | Notifiable = null; 75 | } 76 | 77 | public abstract void Start(); 78 | 79 | public object Clone() 80 | { 81 | return this.MemberwiseClone(); 82 | } 83 | 84 | #endregion 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/EventLogReceiver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using Log2Window.Log; 6 | using System.Collections.Generic; 7 | using System.Windows.Forms; 8 | using System.Threading; 9 | 10 | namespace Log2Window.Receiver 11 | { 12 | [Serializable] 13 | [DisplayName("Windows Event Log")] 14 | public class EventLogReceiver : BaseReceiver 15 | { 16 | [NonSerialized] 17 | private EventLog[] _eventLogs; 18 | 19 | private string _logName; 20 | private string _machineName = "."; 21 | private string _source; 22 | private bool _appendHostNameToLogger = true; 23 | private bool _showFromBeginning = true; 24 | 25 | 26 | [Category("Configuration")] 27 | [DisplayName("Event Log Name")] 28 | [Description("The name of the log on the specified computer. Such as 'Application', 'System', 'Security'. Leave empty to show all logs.(Need administrator.)")] 29 | public string LogName 30 | { 31 | get { return _logName; } 32 | set { _logName = value; } 33 | } 34 | 35 | [Category("Configuration")] 36 | [DisplayName("Machine Name")] 37 | [Description("The computer on which the log exists.")] 38 | public string MachineName 39 | { 40 | get { return _machineName; } 41 | set { _machineName = value; } 42 | } 43 | 44 | [Category("Configuration")] 45 | [DisplayName("Event Log Source")] 46 | [Description("The source of event log entries. Such as 'Windows Error Reporting'. Leave empty to show all source in the log.")] 47 | public string Source 48 | { 49 | get { return _source; } 50 | set { _source = value; } 51 | } 52 | 53 | [Category("Behavior")] 54 | [DisplayName("Append Machine Name to Logger")] 55 | [Description("Append the remote Machine Name to the Logger Name.")] 56 | public bool AppendHostNameToLogger 57 | { 58 | get { return _appendHostNameToLogger; } 59 | set { _appendHostNameToLogger = value; } 60 | } 61 | 62 | [Category("Configuration")] 63 | [DisplayName("Show from Beginning")] 64 | [Description("Show all log messages from the beginning (not just newly added log messages.)")] 65 | [DefaultValue(true)] 66 | public bool ShowFromBeginning 67 | { 68 | get { return _showFromBeginning; } 69 | set 70 | { 71 | _showFromBeginning = value; 72 | } 73 | } 74 | 75 | //[NonSerialized] 76 | //private string _baseLoggerName; 77 | 78 | 79 | #region Overrides of BaseReceiver 80 | 81 | [Browsable(false)] 82 | public override string TextEncoding 83 | { 84 | get; 85 | set; 86 | } 87 | 88 | [Browsable(false)] 89 | public override string SampleClientConfig 90 | { 91 | get 92 | { 93 | return "Use Log2Window to display the Windows Event Logs." + Environment.NewLine + 94 | "Note that the Thread column is used to display the Instance ID (Event ID)."; 95 | } 96 | } 97 | 98 | public override void Initialize() 99 | { 100 | //NonSerialized field must be initilized here. 101 | _waitReadExistingEvengLogs = new ManualResetEvent(false); 102 | if (String.IsNullOrEmpty(MachineName)) 103 | MachineName = "."; 104 | } 105 | 106 | public override void Start() 107 | { 108 | if (String.IsNullOrEmpty(LogName)) 109 | { 110 | _eventLogs = EventLog.GetEventLogs(); 111 | } 112 | else 113 | { 114 | _eventLogs = new EventLog[1]; 115 | if (string.IsNullOrEmpty(Source)) 116 | { 117 | _eventLogs[0] = new EventLog(LogName, MachineName); 118 | } 119 | else 120 | { 121 | _eventLogs[0] = new EventLog(LogName, MachineName, Source); 122 | } 123 | } 124 | 125 | StartListen(); 126 | 127 | ReadExistingEvengLogs(); 128 | } 129 | 130 | private void StartListen() 131 | { 132 | foreach (var eventLog in _eventLogs) 133 | { 134 | try 135 | { 136 | //sender is not EventLog type, use lamda expresstion to get outer eventLog variable. 137 | eventLog.EntryWritten += delegate (object sender, EntryWrittenEventArgs entryWrittenEventArgs) 138 | { 139 | // If have not finished reading existing EvengLogs, wait until it finished. 140 | _waitReadExistingEvengLogs.WaitOne(); 141 | 142 | var entry = entryWrittenEventArgs.Entry; 143 | ParseEventLogEntry(eventLog, entry); 144 | }; 145 | 146 | eventLog.EnableRaisingEvents = true; 147 | } 148 | catch (Exception ex) 149 | { 150 | Utils.log.Error(ex.Message, ex); 151 | System.Threading.ThreadPool.QueueUserWorkItem(delegate (object ob) 152 | { 153 | MessageBox.Show(ex.Message, "Warn", MessageBoxButtons.OK, MessageBoxIcon.Warning); 154 | }); 155 | } 156 | } 157 | } 158 | 159 | [NonSerialized] 160 | ManualResetEvent _waitReadExistingEvengLogs; 161 | private void ReadExistingEvengLogs() 162 | { 163 | List> data = new List>(); 164 | if (ShowFromBeginning) 165 | { 166 | foreach (var eventLog in _eventLogs) 167 | { 168 | try 169 | { 170 | foreach (EventLogEntry entry in eventLog.Entries) 171 | { 172 | if (!string.IsNullOrEmpty(this.Source)) 173 | { 174 | if (entry.Source != this.Source) 175 | { 176 | continue; 177 | } 178 | } 179 | data.Add(Tuple.Create(eventLog, entry)); 180 | } 181 | } 182 | catch (Exception ex) 183 | { 184 | Utils.log.Error(ex.Message, ex); 185 | } 186 | 187 | } 188 | 189 | data = data.OrderBy(x => x.Item2.TimeGenerated).ThenBy(x => x.Item2.Index).ToList(); 190 | 191 | foreach (var item in data) 192 | { 193 | ParseEventLogEntry(item.Item1, item.Item2); 194 | } 195 | } 196 | 197 | _waitReadExistingEvengLogs.Set(); 198 | } 199 | 200 | public override void Terminate() 201 | { 202 | foreach (var eventLog in _eventLogs) 203 | { 204 | eventLog.Dispose(); 205 | } 206 | 207 | _eventLogs = null; 208 | } 209 | 210 | #endregion 211 | 212 | private void ParseEventLogEntry(EventLog eventLog, EventLogEntry entry) 213 | { 214 | LogMessage logMsg = new LogMessage(); 215 | var baseName = "EventLog." + eventLog.Log; 216 | if (AppendHostNameToLogger) 217 | { 218 | baseName = "EventLog_" + (this.MachineName == "." ? "local" : this.MachineName) + "." + eventLog.Log; 219 | } 220 | logMsg.RootLoggerName = baseName; 221 | logMsg.LoggerName = String.IsNullOrEmpty(entry.Source) 222 | ? baseName 223 | : String.Format("{0}.{1}", baseName, entry.Source); 224 | 225 | logMsg.Message = entry.Message; 226 | logMsg.TimeStamp = entry.TimeGenerated; 227 | logMsg.Level = LogUtils.GetLogLevelInfo(GetLogLevel(entry.EntryType)); 228 | logMsg.ThreadName = entry.InstanceId.ToString(); 229 | 230 | if (!String.IsNullOrEmpty(entry.Category)) 231 | logMsg.Properties.Add("Category", entry.Category); 232 | if (!String.IsNullOrEmpty(entry.UserName)) 233 | logMsg.Properties.Add("User Name", entry.UserName); 234 | 235 | if (Notifiable != null) 236 | Notifiable.Notify(logMsg); 237 | } 238 | 239 | private static LogLevel GetLogLevel(EventLogEntryType entryType) 240 | { 241 | switch (entryType) 242 | { 243 | case EventLogEntryType.Warning: return LogLevel.Warn; 244 | case EventLogEntryType.FailureAudit: 245 | case EventLogEntryType.Error: return LogLevel.Error; 246 | case EventLogEntryType.SuccessAudit: 247 | case EventLogEntryType.Information: return LogLevel.Info; 248 | default: 249 | return LogLevel.None; 250 | } 251 | } 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/FileReceiver.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/Receiver/FileReceiver.cs -------------------------------------------------------------------------------- /src/Log2Window/Receiver/IReceiver.cs: -------------------------------------------------------------------------------- 1 | using Log2Window.Log; 2 | 3 | 4 | namespace Log2Window.Receiver 5 | { 6 | public interface IReceiver 7 | { 8 | string SampleClientConfig { get; } 9 | string DisplayName { get; } 10 | 11 | void Initialize(); 12 | void Start(); 13 | void Terminate(); 14 | 15 | void Attach(ILogMessageNotifiable notifiable); 16 | void Stop(); 17 | 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/MsmqReceiver.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.ComponentModel; 3 | //using System.IO; 4 | //using System.Text; 5 | //using System.Threading; 6 | //using System.Messaging; 7 | 8 | //using Log2Window.Log; 9 | 10 | 11 | //namespace Log2Window.Receiver 12 | //{ 13 | 14 | // [Serializable] 15 | // [DisplayName("Windows Message Queue (MSMQ)")] 16 | // public class MsmqReceiver : BaseReceiver 17 | // { 18 | // [NonSerialized] 19 | // private MessageQueue _queue; 20 | 21 | // [NonSerialized] 22 | // private Timer _queueCreationCheckTimer; 23 | 24 | // [NonSerialized] private const int QueueCheckTimerDelayAndInterval = 5000; 25 | 26 | 27 | // private string _queueName = @".\private$\log4net"; 28 | 29 | // [Category("Configuration")] 30 | // [DisplayName("Queue Name")] 31 | // [DefaultValue(@".\private$\log4net")] 32 | // [Description(@"Name of the queue to create. I.e. .\private$\log4net")] 33 | // public string QueueName 34 | // { 35 | // get { return _queueName; } 36 | // set { _queueName = value; } 37 | // } 38 | 39 | // [Category("Configuration")] 40 | // [DisplayName("Create Queue")] 41 | // [Description("Determines how to handle queue creation. If true and the queue does not exist it will be created. If false and the queue does not exist the receiver will wait for the queue to be created.")] 42 | // public bool Create { get; set; } 43 | 44 | // [Category("Configuration")] 45 | // public bool Transactional { get; set; } 46 | 47 | 48 | // private bool _bulkProcessBackedUpMessages = true; 49 | 50 | // [Category("Behavior")] 51 | // [DefaultValue(true)] 52 | // [DisplayName("Bulk Process Backed Up Messages")] 53 | // [Description("If true multiple messages in the queue are processed as one update to the log viewer. This improves the performance of the viewer")] 54 | // public bool BulkProcessBackedUpMessages 55 | // { 56 | // get { return _bulkProcessBackedUpMessages;} 57 | // set { _bulkProcessBackedUpMessages = value; } 58 | // } 59 | 60 | 61 | // [Browsable(false)] 62 | // public override string SampleClientConfig 63 | // { 64 | // get 65 | // { 66 | // return 67 | // "Configuration for NLog:" + Environment.NewLine + 68 | // "" + Environment.NewLine + 71 | // Environment.NewLine + Environment.NewLine + 72 | // "Configuration for log4net:" + Environment.NewLine + 73 | // Environment.NewLine + 74 | // "NOTE: log4net (1.2.10) does not include an MSMQ appender. The following configuration is based on the MSMQ Appender in '.\\examples\\net\\1.0\\Appenders\\SampleAppendersApp\\cs\\src' that is included in the log4net download."+ 75 | // Environment.NewLine + Environment.NewLine + 76 | // "" + 77 | // Environment.NewLine + 78 | // "\t" + Environment.NewLine + 79 | // "\t" + Environment.NewLine + 80 | // "\t" + Environment.NewLine + 81 | // ""; 82 | // } 83 | // } 84 | 85 | 86 | // /// 87 | // /// 88 | // /// 89 | // public override void Initialize() 90 | // { 91 | // if (!MessageQueue.Exists(QueueName)) 92 | // { 93 | // if (Create) 94 | // { 95 | // MessageQueue.Create(QueueName, Transactional); 96 | // } 97 | // else 98 | // { 99 | // /* 100 | // * Start the queue check timer. Should the time be configurable? 101 | // */ 102 | // _queueCreationCheckTimer = new Timer(QueueCreationCheckTimerFunction, this, 103 | // QueueCheckTimerDelayAndInterval, 104 | // QueueCheckTimerDelayAndInterval); 105 | // return; 106 | // } 107 | // } 108 | 109 | // Start(); 110 | // } 111 | 112 | 113 | 114 | // /// 115 | // /// 116 | // /// 117 | // private void Start() 118 | // { 119 | 120 | // _queue = new MessageQueue(QueueName); 121 | 122 | // _queue.ReceiveCompleted += delegate(Object source, ReceiveCompletedEventArgs asyncResult) 123 | // { 124 | // try 125 | // { 126 | // // End the asynchronous receive operation. 127 | // Message m = ((MessageQueue)source).EndReceive(asyncResult.AsyncResult); 128 | 129 | // if (Notifiable != null) 130 | // { 131 | // string loggingEvent = Encoding.ASCII.GetString(((MemoryStream)m.BodyStream).ToArray()); 132 | // LogMessage logMsg = ReceiverUtils.ParseLog4JXmlLogEvent(loggingEvent, "MSMQLogger"); 133 | // logMsg.LoggerName = string.Format("{0}_{1}", QueueName.TrimStart('.'), logMsg.LoggerName); 134 | // logMsg.RootLoggerName = QueueName; 135 | // Notifiable.Notify(logMsg); 136 | // } 137 | 138 | 139 | // if (BulkProcessBackedUpMessages) 140 | // { 141 | // Message[] all = ((MessageQueue) source).GetAllMessages(); 142 | // if (all.Length > 0) 143 | // { 144 | // int numberofmessages = all.Length > 1000 ? 1000 : all.Length; 145 | 146 | // LogMessage[] logs = new LogMessage[numberofmessages]; 147 | 148 | // for (int i = 0; i < numberofmessages; i++) 149 | // { 150 | // Message thisone = ((MessageQueue) source).Receive(); 151 | 152 | // string loggingEvent = 153 | // Encoding.ASCII.GetString(((MemoryStream) thisone.BodyStream).ToArray()); 154 | // LogMessage logMsg = ReceiverUtils.ParseLog4JXmlLogEvent(loggingEvent, "MSMQLogger"); 155 | // logMsg.LoggerName = string.Format("{0}_{1}", QueueName.TrimStart('.'), logMsg.LoggerName); 156 | // logs[i] = logMsg; 157 | // } 158 | 159 | // Notifiable.Notify(logs); 160 | // } 161 | // } 162 | 163 | // ((MessageQueue)source).BeginReceive(); 164 | // } 165 | // catch (MessageQueueException ex) 166 | // { 167 | // Utils.log.Error(ex.Message, ex); 168 | // // Handle sources of MessageQueueException. 169 | // } 170 | // }; 171 | 172 | // _queue.BeginReceive(); 173 | // } 174 | 175 | 176 | 177 | 178 | // /// 179 | // /// 180 | // /// 181 | // public override void Terminate() 182 | // { 183 | // /* 184 | // * Are we going to have any issues if we are processing a receive complete or will 185 | // * MSMQ protect us? 186 | // */ 187 | // if (_queue != null) 188 | // { 189 | // _queue.Close(); 190 | // } 191 | // } 192 | 193 | 194 | // /// 195 | // /// 196 | // /// 197 | // /// 198 | // private static void QueueCreationCheckTimerFunction(object state) 199 | // { 200 | // //TODOCJH: If this timer gets called then we did not finish the job before the maximum allowable time. 201 | // //_logger.Fatal("JobMaxExecutionTimerFunction"); 202 | 203 | // MsmqReceiver rcv = state as MsmqReceiver; 204 | // if ((rcv != null) && MessageQueue.Exists(rcv.QueueName)) 205 | // { 206 | // rcv._queueCreationCheckTimer.Change(Timeout.Infinite, Timeout.Infinite); 207 | // rcv._queueCreationCheckTimer.Dispose(); 208 | // rcv.Start(); 209 | // } 210 | // } 211 | // } 212 | //} 213 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/ReceiverFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Xml; 8 | using System.Linq; 9 | using Log2Window.Log; 10 | 11 | namespace Log2Window.Receiver 12 | { 13 | public class ReceiverFactory 14 | { 15 | public class ReceiverInfo 16 | { 17 | public string Name; 18 | public Type Type; 19 | 20 | public override string ToString() 21 | { 22 | return Name; 23 | } 24 | } 25 | 26 | private static ReceiverFactory _instance; 27 | 28 | private readonly Dictionary _receiverTypes = new Dictionary(); 29 | 30 | 31 | private static readonly string ReceiverInterfaceName = typeof(IReceiver).FullName; 32 | 33 | private ReceiverFactory() 34 | { 35 | // Get all the possible receivers by enumerating all the types implementing the interface 36 | Assembly assembly = Assembly.GetAssembly(typeof(IReceiver)); 37 | Type[] types = assembly.GetTypes(); 38 | foreach (Type type in types) 39 | { 40 | // Skip abstract types 41 | if (type.IsAbstract) 42 | continue; 43 | 44 | Type[] findInterfaces = type.FindInterfaces((typeObj, o) => (typeObj.ToString() == ReceiverInterfaceName), null); 45 | if (findInterfaces.Length < 1) 46 | continue; 47 | 48 | AddReceiver(type); 49 | } 50 | 51 | _receiverTypes = _receiverTypes.OrderBy(x => x.Value.Name).ToDictionary(x => x.Key, x => x.Value); 52 | } 53 | 54 | private void AddReceiver(Type type) 55 | { 56 | var info = new ReceiverInfo { Name = ReceiverUtils.GetTypeDescription(type), Type = type }; 57 | _receiverTypes.Add(type.FullName, info); 58 | } 59 | 60 | public static ReceiverFactory Instance 61 | { 62 | get { return _instance ?? (_instance = new ReceiverFactory()); } 63 | } 64 | 65 | public Dictionary ReceiverTypes 66 | { 67 | get { return _receiverTypes; } 68 | } 69 | 70 | public IReceiver Create(string typeStr) 71 | { 72 | IReceiver receiver = null; 73 | 74 | ReceiverInfo info; 75 | if (_receiverTypes.TryGetValue(typeStr, out info)) 76 | { 77 | receiver = Activator.CreateInstance(info.Type) as IReceiver; 78 | } 79 | 80 | return receiver; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/ReceiverUtils.cs: -------------------------------------------------------------------------------- 1 | using Log2Window.Log; 2 | using System; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | using System.Xml; 8 | 9 | namespace Log2Window.Receiver 10 | { 11 | public static class ReceiverUtils 12 | { 13 | static readonly DateTime s1970 = new DateTime(1970, 1, 1); 14 | 15 | public static string GetTypeDescription(Type type) 16 | { 17 | var attr = (DisplayNameAttribute)Attribute.GetCustomAttribute(type, typeof(DisplayNameAttribute), true); 18 | return attr != null ? attr.DisplayName : type.ToString(); 19 | } 20 | 21 | /// 22 | /// We can share settings to improve performance 23 | /// 24 | static readonly XmlReaderSettings XmlSettings = CreateSettings(); 25 | 26 | static XmlReaderSettings CreateSettings() 27 | { 28 | return new XmlReaderSettings { CloseInput = false, ValidationType = ValidationType.None }; 29 | } 30 | 31 | /// 32 | /// We can share parser context to improve performance 33 | /// 34 | static readonly XmlParserContext XmlContext = CreateContext(); 35 | 36 | static XmlParserContext CreateContext() 37 | { 38 | var nt = new NameTable(); 39 | var nsmanager = new XmlNamespaceManager(nt); 40 | nsmanager.AddNamespace("log4j", "http://jakarta.apache.org/log4j/"); 41 | nsmanager.AddNamespace("nlog", "http://nlog-project.org"); 42 | return new XmlParserContext(nt, nsmanager, "elem", XmlSpace.None, Encoding.UTF8); 43 | } 44 | 45 | /// 46 | /// Parse LOG4JXml from xml stream 47 | /// 48 | public static LogMessage ParseLog4JXmlLogEvent(Stream logStream, string defaultLogger) 49 | { 50 | // In case of ungraceful disconnect 51 | // logStream is closed and XmlReader throws the exception, 52 | // which we handle in TcpReceiver 53 | using (var reader = XmlReader.Create(logStream, XmlSettings, XmlContext)) 54 | return ParseLog4JXmlLogEvent(reader, defaultLogger); 55 | } 56 | 57 | // 将不可解析的特殊字符替换为空格. 58 | // https://stackoverflow.com/questions/21053138/c-sharp-hexadecimal-value-0x12-is-an-invalid-character 59 | // 注意, 原回答中, 0x26 也被替换了. 这是错误的. 只应当替换0x1F以下的字符. 因为 " 之类的是表示引号. 等等 60 | static string ReplaceHexadecimalSymbols(string txt) 61 | { 62 | string r = "[\x00-\x08\x0B\x0C\x0E-\x1F]"; 63 | return Regex.Replace(txt, r, " ", RegexOptions.Compiled); 64 | } 65 | 66 | /// 67 | /// Parse LOG4JXml from string 68 | /// 69 | public static LogMessage ParseLog4JXmlLogEvent(string logEvent, string defaultLogger) 70 | { 71 | try 72 | { 73 | logEvent = ReplaceHexadecimalSymbols(logEvent); 74 | using (var reader = new XmlTextReader(logEvent, XmlNodeType.Element, XmlContext)) 75 | return ParseLog4JXmlLogEvent(reader, defaultLogger); 76 | } 77 | catch (Exception ex) 78 | { 79 | Utils.log.Error("ParseLog4JXmlLogEvent: " + ex.Message + "\nraw message:\n" + logEvent, ex); 80 | return new LogMessage 81 | { 82 | // Create a simple log message with some default values 83 | LoggerName = defaultLogger, 84 | RootLoggerName = defaultLogger, 85 | ThreadName = "NA", 86 | Message = logEvent, 87 | TimeStamp = DateTime.Now, 88 | Level = LogLevels.Instance[LogLevel.Info], 89 | ExceptionString = ex.Message 90 | }; 91 | } 92 | } 93 | 94 | /// 95 | /// Here we expect the log event to use the log4j schema. 96 | /// Sample: 97 | /// 98 | /// This is an Message 99 | /// 100 | /// 101 | /// 102 | /// 103 | /// 104 | /// 105 | /// 106 | /// 107 | /// 108 | /// Implementation inspired from: http://geekswithblogs.net/kobush/archive/2006/04/20/75717.aspx 109 | /// 110 | public static LogMessage ParseLog4JXmlLogEvent(XmlReader reader, string defaultLogger) 111 | { 112 | var logMsg = new LogMessage(); 113 | 114 | reader.Read(); 115 | if ((reader.MoveToContent() != XmlNodeType.Element) || (reader.Name != "log4j:event")) 116 | throw new Exception("The Log Event is not a valid log4j Xml block."); 117 | 118 | logMsg.LoggerName = reader.GetAttribute("logger"); 119 | logMsg.Level = LogLevels.Instance[reader.GetAttribute("level")]; 120 | logMsg.ThreadName = reader.GetAttribute("thread"); 121 | 122 | long timeStamp; 123 | if (long.TryParse(reader.GetAttribute("timestamp"), out timeStamp)) 124 | logMsg.TimeStamp = s1970.AddMilliseconds(timeStamp).ToLocalTime(); 125 | 126 | int eventDepth = reader.Depth; 127 | reader.Read(); 128 | while (reader.Depth > eventDepth) 129 | { 130 | if (reader.MoveToContent() == XmlNodeType.Element) 131 | { 132 | switch (reader.Name) 133 | { 134 | case "log4j:message": 135 | logMsg.Message = reader.ReadString(); 136 | break; 137 | 138 | case "log4j:throwable": 139 | var exValue = reader.ReadString(); 140 | logMsg.ExceptionString = exValue; 141 | break; 142 | 143 | case "log4j:locationInfo": 144 | logMsg.CallSiteClass = reader.GetAttribute("class"); 145 | logMsg.CallSiteMethod = reader.GetAttribute("method"); 146 | logMsg.SourceFileName = reader.GetAttribute("file"); 147 | uint sourceFileLine; 148 | if (uint.TryParse(reader.GetAttribute("line"), out sourceFileLine)) 149 | logMsg.SourceFileLineNr = sourceFileLine; 150 | break; 151 | case "nlog:eventSequenceNumber": 152 | ulong sequenceNumber; 153 | if (ulong.TryParse(reader.ReadString(), out sequenceNumber)) 154 | logMsg.SequenceNr = sequenceNumber; 155 | break; 156 | case "nlog:locationInfo": 157 | break; 158 | 159 | case "log4j:properties": 160 | reader.Read(); 161 | while (reader.MoveToContent() == XmlNodeType.Element 162 | && reader.Name == "log4j:data") 163 | { 164 | string name = reader.GetAttribute("name"); 165 | string value = reader.GetAttribute("value"); 166 | if (name != null && name.ToLower().Equals("exceptions")) 167 | { 168 | logMsg.ExceptionString = value; 169 | } 170 | else 171 | { 172 | logMsg.Properties[name] = value; 173 | } 174 | 175 | reader.Read(); 176 | } 177 | 178 | break; 179 | } 180 | } 181 | reader.Read(); 182 | } 183 | 184 | return logMsg; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/RemotingReceiver.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.ComponentModel; 3 | //using System.Collections; 4 | //using System.Runtime.Remoting; 5 | //using System.Runtime.Remoting.Channels; 6 | //using System.Runtime.Remoting.Channels.Tcp; 7 | //using System.Runtime.Serialization; 8 | //using System.Runtime.Serialization.Formatters; 9 | 10 | //using log4net.Appender; 11 | //using log4net.Core; 12 | 13 | //using Log2Window.Log; 14 | 15 | 16 | //namespace Log2Window.Receiver 17 | //{ 18 | // [Serializable] 19 | // [DisplayName(".NET Remoting")] 20 | // public class RemotingReceiver : BaseReceiver, RemotingAppender.IRemoteLoggingSink, ISerializable 21 | // { 22 | // private const string RemotingReceiverChannelName = "RemotingReceiverChannel"; 23 | 24 | // [NonSerialized] 25 | // private IChannel _channel = null; 26 | 27 | // private string _sinkName = "LoggingSink"; 28 | // private int _port = 7070; 29 | // private bool _appendHostNameToLogger = true; 30 | 31 | 32 | // [Category("Configuration")] 33 | // [DisplayName("Remote Sink Name")] 34 | // public string SinkName 35 | // { 36 | // get { return _sinkName; } 37 | // set { _sinkName = value; } 38 | // } 39 | 40 | // [Category("Configuration")] 41 | // [DisplayName("Remote TCP Port Number")] 42 | // public int Port 43 | // { 44 | // get { return _port; } 45 | // set { _port = value; } 46 | // } 47 | 48 | // [Category("Behavior")] 49 | // [DisplayName("Append Host Name to Logger")] 50 | // [Description("Append the remote Host Name to the Logger Name.")] 51 | // public bool AppendHostNameToLogger 52 | // { 53 | // get { return _appendHostNameToLogger; } 54 | // set { _appendHostNameToLogger = value; } 55 | // } 56 | 57 | 58 | // /// 59 | // /// Default ctor 60 | // /// 61 | // public RemotingReceiver() { } 62 | 63 | // #region ISerializable Members 64 | 65 | // /// 66 | // /// Constructor for Serialization 67 | // /// N.B: Explicit implementation of ISerializable to mask SecurityIdentity Property of mother class 68 | // /// 69 | // public RemotingReceiver(SerializationInfo info, StreamingContext context) 70 | // { 71 | // _sinkName = info.GetString("SinkName"); 72 | // _port = info.GetInt32("Port"); 73 | // } 74 | 75 | // /// 76 | // /// ISerializable method override for deserialization 77 | // /// N.B: Explicit implementation of ISerializable to mask SecurityIdentity Property of mother class 78 | // /// 79 | // public void GetObjectData(SerializationInfo info, StreamingContext context) 80 | // { 81 | // info.AddValue("SinkName", _sinkName); 82 | // info.AddValue("Port", _port); 83 | // } 84 | 85 | // #endregion 86 | 87 | 88 | // #region IReceiver Members 89 | 90 | // [Browsable(false)] 91 | // public override string SampleClientConfig 92 | // { 93 | // get 94 | // { 95 | // return 96 | // "Configuration for log4net:" + Environment.NewLine + 97 | // "" + Environment.NewLine + 98 | // " " + Environment.NewLine + 99 | // " " + Environment.NewLine + 100 | // " " + Environment.NewLine + 101 | // " " + Environment.NewLine + 102 | // " " + Environment.NewLine + 103 | // " " + Environment.NewLine + 104 | // ""; 105 | // } 106 | // } 107 | 108 | // public override void Initialize() 109 | // { 110 | // // Channel already open? 111 | // _channel = ChannelServices.GetChannel(RemotingReceiverChannelName); 112 | 113 | 114 | // if (_channel == null) 115 | // { 116 | // // Allow clients to receive complete Remoting exception information 117 | // if (RemotingConfiguration.CustomErrorsEnabled(true)) 118 | // RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off; 119 | 120 | // // Create TCP Channel 121 | // try 122 | // { 123 | // BinaryClientFormatterSinkProvider clientProvider = null; 124 | // BinaryServerFormatterSinkProvider serverProvider = 125 | // new BinaryServerFormatterSinkProvider(); 126 | // serverProvider.TypeFilterLevel = TypeFilterLevel.Full; 127 | 128 | // IDictionary props = new Hashtable(); 129 | // props["port"] = _port.ToString(); 130 | // props["name"] = RemotingReceiverChannelName; 131 | // props["typeFilterLevel"] = TypeFilterLevel.Full; 132 | // _channel = new TcpChannel(props, clientProvider, serverProvider); 133 | 134 | // ChannelServices.RegisterChannel(_channel, false); 135 | // } 136 | // catch (Exception ex) 137 | // { 138 | // throw new Exception("Remoting TCP Channel Initialization failed", ex); 139 | // } 140 | // } 141 | 142 | // Type serverType = RemotingServices.GetServerTypeForUri(_sinkName); 143 | // if ((serverType == null) || (serverType != typeof(RemotingAppender.IRemoteLoggingSink))) 144 | // { 145 | // // Marshal Receiver 146 | // try 147 | // { 148 | // RemotingServices.Marshal(this, _sinkName, typeof(RemotingAppender.IRemoteLoggingSink)); 149 | // } 150 | // catch (Exception ex) 151 | // { 152 | // throw new Exception("Remoting Marshal failed", ex); 153 | // } 154 | // } 155 | // } 156 | 157 | // public override void Terminate() 158 | // { 159 | // if (_channel != null) 160 | // ChannelServices.UnregisterChannel(_channel); 161 | // _channel = null; 162 | // } 163 | 164 | // #endregion 165 | 166 | 167 | // #region Override implementation of MarshalByRefObject 168 | 169 | // /// 170 | // /// Obtains a lifetime service object to control the lifetime 171 | // /// policy for this instance. 172 | // /// 173 | // /// null to indicate that this instance should live forever. 174 | // /// 175 | // /// 176 | // /// Obtains a lifetime service object to control the lifetime 177 | // /// policy for this instance. This object should live forever 178 | // /// therefore this implementation returns null. 179 | // /// 180 | // /// 181 | // public override object InitializeLifetimeService() 182 | // { 183 | // return null; 184 | // } 185 | 186 | // #endregion Override implementation of MarshalByRefObject 187 | 188 | 189 | // #region Implementation of IRemoteLoggingSink 190 | 191 | // public void LogEvents(LoggingEvent[] events) 192 | // { 193 | // if ((events == null) || (events.Length == 0) || (Notifiable == null)) 194 | // return; 195 | 196 | // LogMessage[] logMsgs = new LogMessage[events.Length]; 197 | // for (int i = 0; i < events.Length; i++) 198 | // logMsgs[i] = CreateLogMessage(events[i]); 199 | 200 | // Notifiable.Notify(logMsgs); 201 | // } 202 | 203 | // #endregion Implementation of IRemoteLoggingSink 204 | 205 | 206 | // protected LogMessage CreateLogMessage(LoggingEvent logEvent) 207 | // { 208 | // LogMessage logMsg = new LogMessage(); 209 | // if (_appendHostNameToLogger && logEvent.Properties.Contains(LoggingEvent.HostNameProperty)) 210 | // { 211 | // logMsg.RootLoggerName = logEvent.Properties[LoggingEvent.HostNameProperty].ToString(); 212 | // logMsg.LoggerName = String.Format("[Host: {0}].{1}", logEvent.Properties[LoggingEvent.HostNameProperty], 213 | // logEvent.LoggerName); 214 | // } 215 | // else 216 | // { 217 | // logMsg.RootLoggerName = logEvent.LoggerName; 218 | // logMsg.LoggerName = logEvent.LoggerName; 219 | // } 220 | 221 | // logMsg.ThreadName = logEvent.ThreadName; 222 | // logMsg.Message = logEvent.RenderedMessage; 223 | // logMsg.TimeStamp = logEvent.TimeStamp; 224 | // logMsg.Level = LogUtils.GetLogLevelInfo(logEvent.Level.Value); 225 | 226 | // // Per LoggingEvent.ExceptionObject, the exception object is not serialized, but the exception 227 | // // text is available through LoggingEvent.GetExceptionString 228 | // logMsg.ExceptionString = logEvent.GetExceptionString(); 229 | 230 | // // Copy properties as string 231 | // foreach (DictionaryEntry entry in logEvent.Properties) 232 | // { 233 | // if ((entry.Key == null) || (entry.Value == null)) 234 | // continue; 235 | 236 | // logMsg.Properties.Add(entry.Key.ToString(), entry.Value.ToString()); 237 | // } 238 | 239 | // return logMsg; 240 | // } 241 | // } 242 | //} 243 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/SLPolicyServerReceiver.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.ComponentModel; 3 | //using System.Net; 4 | //using System.Net.Sockets; 5 | //using System.Text; 6 | 7 | //namespace Log2Window.Receiver 8 | //{ 9 | // [Serializable] 10 | // [DisplayName("Silverlight Socket Policy")] 11 | // public class SLPolicyServerReceiver : BaseReceiver 12 | // { 13 | // [NonSerialized] 14 | // private Socket _socket; 15 | 16 | // int _portFrom = 4502; 17 | // int _portTo = 4532; 18 | 19 | // [Category("Configuration")] 20 | // [DisplayName("TCP Port From")] 21 | // [DefaultValue(4502)] 22 | // public int PortFrom 23 | // { 24 | // get { return _portFrom; } 25 | // set { _portFrom = value; } 26 | // } 27 | 28 | // [Category("Configuration")] 29 | // [DisplayName("TCP Port To")] 30 | // [DefaultValue(4532)] 31 | // public int PortTo 32 | // { 33 | // get { return _portTo; } 34 | // set { _portTo = value; } 35 | // } 36 | 37 | // #region IReceiver Members 38 | 39 | // [Browsable(false)] 40 | // public override string SampleClientConfig 41 | // { 42 | // get 43 | // { 44 | // return "This receiver allows Silverlight client to use sockets"; 45 | // } 46 | // } 47 | 48 | // const string PolicyRequestString = ""; 49 | // const string PolicyTemplate = 50 | // @" 51 | // 52 | // 53 | // 54 | // 55 | // 56 | // 57 | // 58 | // 59 | // 60 | //"; 61 | 62 | // byte[] _policy; 63 | 64 | // public override void Initialize() 65 | // { 66 | // if (_socket != null) return; 67 | 68 | // _policy = Encoding.UTF8.GetBytes(string.Format(PolicyTemplate, _portFrom, _portTo)); 69 | 70 | // _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 71 | // _socket.ExclusiveAddressUse = true; 72 | // _socket.Bind(new IPEndPoint(IPAddress.Any, 943)); 73 | // _socket.Listen(100); 74 | 75 | // var args = new SocketAsyncEventArgs(); 76 | // args.Completed += AcceptAsyncCompleted; 77 | 78 | // _socket.AcceptAsync(args); 79 | // } 80 | 81 | // void AcceptAsyncCompleted(object sender, SocketAsyncEventArgs e) 82 | // { 83 | // if (_socket == null) return; 84 | 85 | // var socket = e.AcceptSocket; 86 | 87 | // e.AcceptSocket = null; 88 | // _socket.AcceptAsync(e); 89 | 90 | // ProcessRequest(socket); 91 | // } 92 | 93 | // void ProcessRequest(Socket socket) 94 | // { 95 | // using (var client = new TcpClient { Client = socket, ReceiveTimeout = 5000 }) 96 | // using (var s = client.GetStream()) 97 | // { 98 | // var buffer = new byte[PolicyRequestString.Length]; 99 | // s.Read(buffer, 0, buffer.Length); 100 | // s.Write(_policy, 0, _policy.Length); 101 | // } 102 | // } 103 | 104 | // public override void Terminate() 105 | // { 106 | // if (_socket == null) return; 107 | 108 | // _socket.Close(); 109 | // _socket = null; 110 | // } 111 | 112 | // #endregion 113 | // } 114 | //} 115 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/TcpReceiver.cs: -------------------------------------------------------------------------------- 1 | using Log2Window.Log; 2 | using System; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Net; 7 | using System.Net.Sockets; 8 | using System.Text; 9 | using System.Threading; 10 | 11 | namespace Log2Window.Receiver 12 | { 13 | [Serializable] 14 | [DisplayName("TCP (IP v4 and v6)")] 15 | public class TcpReceiver : BaseReceiver 16 | { 17 | #region Port Property 18 | 19 | int _port = 4505; 20 | [Category("Configuration")] 21 | [DisplayName("TCP Port Number")] 22 | [DefaultValue(4505)] 23 | public int Port 24 | { 25 | get { return _port; } 26 | set { _port = value; } 27 | } 28 | 29 | #endregion 30 | 31 | #region IpV6 Property 32 | 33 | bool _ipv6; 34 | [Category("Configuration")] 35 | [DisplayName("Use IPv6 Addresses")] 36 | [DefaultValue(false)] 37 | public bool IpV6 38 | { 39 | get { return _ipv6; } 40 | set { _ipv6 = value; } 41 | } 42 | 43 | private int _bufferSize = 65536; 44 | [Category("Configuration")] 45 | [DisplayName("Receive Buffer Size")] 46 | [DefaultValue(65536)] 47 | public int BufferSize 48 | { 49 | get { return _bufferSize; } 50 | set { _bufferSize = Math.Max(65536, value); } 51 | } 52 | 53 | bool _useRemoteIPAsNamespacePrefix; 54 | [Category("Configuration")] 55 | [DisplayName("Use Remote IP As Namespace Prefix.")] 56 | [DefaultValue(false)] 57 | public bool UseRemoteIPAsNamespacePrefix 58 | { 59 | get { return _useRemoteIPAsNamespacePrefix; } 60 | set { _useRemoteIPAsNamespacePrefix = value; } 61 | } 62 | 63 | #endregion 64 | 65 | #region IReceiver Members 66 | 67 | [Browsable(false)] 68 | public override string SampleClientConfig 69 | { 70 | get 71 | { 72 | return 73 | @"Configuration for NLog: 74 | 75 | 76 | Configuration for log4net: 77 | Please using AlanThinker.MyLog4net.TcpAppender.cs in the ExampleProject\TestLog4net project. 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | ".Replace("'", "\"").Replace("\n", Environment.NewLine); 92 | } 93 | } 94 | 95 | [NonSerialized] 96 | Socket _socket; 97 | 98 | public override void Initialize() 99 | { 100 | if (_socket != null) return; 101 | 102 | _socket = new Socket(_ipv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 103 | _socket.ExclusiveAddressUse = true; 104 | _socket.Bind(new IPEndPoint(_ipv6 ? IPAddress.IPv6Any : IPAddress.Any, _port)); 105 | _socket.Listen(100); 106 | _socket.ReceiveBufferSize = _bufferSize; 107 | } 108 | 109 | public override void Start() 110 | { 111 | var args = new SocketAsyncEventArgs(); 112 | args.Completed += AcceptAsyncCompleted; 113 | 114 | _socket.AcceptAsync(args); 115 | } 116 | 117 | void AcceptAsyncCompleted(object sender, SocketAsyncEventArgs e) 118 | { 119 | try 120 | { 121 | if (_socket == null || e.SocketError != SocketError.Success) return; 122 | 123 | //Must start a new thread to prcess data, otherwise can only process only one connection. 124 | new Thread(ProcessReceivedData) { IsBackground = true }.Start(e.AcceptSocket); 125 | 126 | e.AcceptSocket = null; 127 | _socket.AcceptAsync(e); 128 | } 129 | catch (Exception ex) 130 | { 131 | Utils.log.Error(ex.Message, ex); 132 | } 133 | } 134 | 135 | static char[] log4jEndTag = "".ToCharArray(); 136 | void ProcessReceivedData(object newSocket) 137 | { 138 | try 139 | { 140 | using (var socket = (Socket)newSocket) 141 | using (var ns = new NetworkStream(socket, FileAccess.Read, false)) 142 | while (_socket != null) 143 | { 144 | using (StreamReader sr = new StreamReader(ns, this.EncodingObject)) 145 | { 146 | //NetworkStream may contain multiple log4j:event, if the tcp send message very frequently. 147 | StringBuilder sb = new StringBuilder(); 148 | 149 | int temp; 150 | while (_socket != null 151 | && (temp = sr.Read()) != -1) 152 | { 153 | sb.Append((char)temp); 154 | if (IsEndWith(sb, log4jEndTag)) 155 | { 156 | var str = sb.ToString(); 157 | LogMessage logMsg = ReceiverUtils.ParseLog4JXmlLogEvent(str, "TcpLogger"); 158 | logMsg.RootLoggerName = logMsg.LoggerName; 159 | //logMsg.LoggerName = string.Format(":{1}.{0}", logMsg.LoggerName, _port); 160 | 161 | if (_useRemoteIPAsNamespacePrefix) 162 | { 163 | var ipEndPoint = socket.RemoteEndPoint as IPEndPoint; 164 | if (ipEndPoint != null) 165 | { 166 | logMsg.LoggerName = string.Format("{0}.{1}", ipEndPoint.Address.ToString().Replace('.', '_'), logMsg.LoggerName); 167 | } 168 | else 169 | { 170 | var dnsEndPoint = socket.RemoteEndPoint as DnsEndPoint; 171 | if (dnsEndPoint != null) 172 | { 173 | logMsg.LoggerName = string.Format("{0}.{1}", dnsEndPoint.Host.Replace('.', '_'), logMsg.LoggerName); 174 | } 175 | else 176 | { 177 | // rmove ':' , because same app may have different port number after it restart. 178 | var fullAddress = socket.RemoteEndPoint.ToString(); 179 | var address = fullAddress.Substring(0, fullAddress.IndexOf(":")); 180 | logMsg.LoggerName = string.Format("{0}.{1}", address.Replace('.', '_'), logMsg.LoggerName); 181 | } 182 | } 183 | } 184 | 185 | if (Notifiable != null) 186 | Notifiable.Notify(logMsg); 187 | 188 | sb = new StringBuilder(); 189 | } 190 | 191 | } 192 | } 193 | } 194 | } 195 | catch (IOException ex) 196 | { 197 | Utils.log.Error("ProcessReceivedData " + ex.Message); 198 | } 199 | catch (Exception ex) 200 | { 201 | Utils.log.Error(ex.Message, ex); 202 | } 203 | } 204 | 205 | private bool IsEndWith(StringBuilder sb, char[] str) 206 | { 207 | if (sb.Length < str.Length) 208 | return false; 209 | 210 | for (int i = str.Length - 1, j = sb.Length - 1; i >= 0; i--, j--) 211 | { 212 | if (str[i] != sb[j]) 213 | { 214 | return false; 215 | } 216 | } 217 | 218 | return true; 219 | } 220 | 221 | public override void Terminate() 222 | { 223 | if (_socket == null) return; 224 | 225 | _socket.Close(); 226 | _socket = null; 227 | } 228 | 229 | #endregion 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/UdpReceiver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Net; 4 | using System.Net.Sockets; 5 | using System.Text; 6 | using System.Threading; 7 | 8 | using Log2Window.Log; 9 | 10 | 11 | namespace Log2Window.Receiver 12 | { 13 | [Serializable] 14 | [DisplayName("UDP (IP v4 and v6)")] 15 | public class UdpReceiver : BaseReceiver 16 | { 17 | [NonSerialized] 18 | private Thread _worker; 19 | [NonSerialized] 20 | private UdpClient _udpClient; 21 | [NonSerialized] 22 | private IPEndPoint _remoteEndPoint; 23 | 24 | private bool _ipv6; 25 | private int _port = 7071; 26 | private string _address = String.Empty; 27 | private int _bufferSize = 1310720; 28 | 29 | 30 | [Category("Configuration")] 31 | [DisplayName("UDP Port Number")] 32 | [DefaultValue(7071)] 33 | public int Port 34 | { 35 | get { return _port; } 36 | set { _port = value; } 37 | } 38 | 39 | [Category("Configuration")] 40 | [DisplayName("Use IPv6 Addresses")] 41 | [DefaultValue(false)] 42 | public bool IpV6 43 | { 44 | get { return _ipv6; } 45 | set { _ipv6 = value; } 46 | } 47 | 48 | [Category("Configuration")] 49 | [DisplayName("Multicast Group Address (Optional)")] 50 | public string Address 51 | { 52 | get { return _address; } 53 | set { _address = value; } 54 | } 55 | 56 | [Category("Configuration")] 57 | [DisplayName("Receive Buffer Size")] 58 | [DefaultValue(1310720)] 59 | public int BufferSize 60 | { 61 | get { return _bufferSize; } 62 | // UDP is not a reliable protocol. So increase the BufferSize to reduce the risk of lost packet. 63 | set { _bufferSize = Math.Max(1310720, value); } 64 | } 65 | 66 | bool _useRemoteIPAsNamespacePrefix; 67 | [Category("Configuration")] 68 | [DisplayName("Use Remote IP As Namespace Prefix.")] 69 | [DefaultValue(false)] 70 | public bool UseRemoteIPAsNamespacePrefix 71 | { 72 | get { return _useRemoteIPAsNamespacePrefix; } 73 | set { _useRemoteIPAsNamespacePrefix = value; } 74 | } 75 | 76 | #region IReceiver Members 77 | 78 | [Browsable(false)] 79 | public override string SampleClientConfig 80 | { 81 | get 82 | { 83 | return 84 | @"Notice! 85 | UDP is not a reliable protocol. 86 | So recommend using AlanThinker.MyLog4net.TcpAppender.cs in the ExampleProject\TestLog4net project. 87 | 88 | Configuration for NLog: 89 | 90 | 91 | Configuration for log4net: 92 | 93 | 94 | 95 | 96 | 97 | 98 | ".Replace("'", "\"").Replace("\n", Environment.NewLine); 99 | } 100 | } 101 | 102 | public override void Initialize() 103 | { 104 | if ((_worker != null) && _worker.IsAlive) 105 | return; 106 | 107 | // Init connexion here, before starting the thread, to know the status now 108 | _remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); 109 | _udpClient = _ipv6 ? new UdpClient(_port, AddressFamily.InterNetworkV6) : new UdpClient(_port); 110 | _udpClient.Client.ReceiveBufferSize = _bufferSize; 111 | if (!String.IsNullOrEmpty(_address)) 112 | _udpClient.JoinMulticastGroup(IPAddress.Parse(_address)); 113 | } 114 | 115 | public override void Start() 116 | { 117 | // We need a working thread 118 | _worker = new Thread(StartUdp); 119 | _worker.IsBackground = true; 120 | _worker.Start(); 121 | } 122 | 123 | public override void Terminate() 124 | { 125 | if (_udpClient != null) 126 | { 127 | _udpClient.Close(); 128 | _udpClient = null; 129 | 130 | _remoteEndPoint = null; 131 | } 132 | 133 | if ((_worker != null) && _worker.IsAlive) 134 | _worker.Abort(); 135 | _worker = null; 136 | } 137 | 138 | #endregion 139 | 140 | public void Clear() 141 | { 142 | } 143 | 144 | private void StartUdp() 145 | { 146 | while ((_udpClient != null) && (_remoteEndPoint != null)) 147 | { 148 | try 149 | { 150 | byte[] buffer = _udpClient.Receive(ref _remoteEndPoint); 151 | string loggingEvent = this.EncodingObject.GetString(buffer); 152 | 153 | //Console.WriteLine(loggingEvent); 154 | // Console.WriteLine("Count: " + count++); 155 | 156 | if (Notifiable == null) 157 | continue; 158 | 159 | LogMessage logMsg = ReceiverUtils.ParseLog4JXmlLogEvent(loggingEvent, "UdpLogger"); 160 | if (_useRemoteIPAsNamespacePrefix) 161 | { 162 | logMsg.RootLoggerName = _remoteEndPoint.Address.ToString().Replace(".", "-"); 163 | logMsg.LoggerName = string.Format("{0}_{1}", _remoteEndPoint.Address.ToString().Replace(".", "-"), logMsg.LoggerName); 164 | } 165 | 166 | if (Notifiable != null) 167 | Notifiable.Notify(logMsg); 168 | } 169 | catch (ThreadAbortException ex) 170 | { 171 | Utils.log.Error("StartUdp " + ex.Message); 172 | Thread.ResetAbort(); 173 | break; 174 | } 175 | catch (Exception ex) 176 | { 177 | Utils.log.Error(ex.Message, ex); 178 | return; 179 | } 180 | } 181 | } 182 | 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/Log2Window/Receiver/WinDebugReceiver.cs: -------------------------------------------------------------------------------- 1 | //using System; 2 | //using System.ComponentModel; 3 | //using System.Diagnostics; 4 | 5 | //using CatchOutputDbg; 6 | 7 | //using Log2Window.Log; 8 | 9 | 10 | //namespace Log2Window.Receiver 11 | //{ 12 | // [Serializable] 13 | // [DisplayName("WinDebug (OutputDebugString)")] 14 | // public class WinDebugReceiver : BaseReceiver 15 | // { 16 | // #region Overrides of BaseReceiver 17 | 18 | // [Browsable(false)] 19 | // public override string SampleClientConfig 20 | // { 21 | // get { return "N/A"; } 22 | // } 23 | 24 | // public override void Initialize() 25 | // { 26 | // DebugMonitor.OnOutputDebugString += DebugMonitor_OnOutputDebugString; 27 | // DebugMonitor.Start(); 28 | // } 29 | 30 | // public override void Terminate() 31 | // { 32 | // DebugMonitor.OnOutputDebugString -= DebugMonitor_OnOutputDebugString; 33 | // DebugMonitor.Stop(); 34 | // } 35 | 36 | // #endregion 37 | 38 | 39 | // void DebugMonitor_OnOutputDebugString(int pid, string text) 40 | // { 41 | // // Trim ending newline (if any) 42 | // if (text.EndsWith(Environment.NewLine)) 43 | // text = text.Substring(0, text.Length - Environment.NewLine.Length); 44 | 45 | // // Replace dots by "middle dots" to preserve Logger namespace 46 | // string processName = GetProcessName(pid); 47 | // processName = processName.Replace('.', '·'); 48 | 49 | // LogMessage logMsg = new LogMessage(); 50 | // logMsg.Message = text; 51 | // logMsg.LoggerName = processName; 52 | // logMsg.LoggerName = String.Format("{0}.{1}", processName, pid); 53 | // logMsg.Level = LogLevels.Instance[LogLevel.Debug]; 54 | // logMsg.ThreadName = pid.ToString(); 55 | // logMsg.TimeStamp = DateTime.Now; 56 | // Notifiable.Notify(logMsg); 57 | // } 58 | 59 | // private static string GetProcessName(int pid) 60 | // { 61 | // if (pid == -1) 62 | // return Process.GetCurrentProcess().ProcessName; 63 | // try 64 | // { 65 | // return Process.GetProcessById(pid).ProcessName; 66 | // } 67 | // catch 68 | // { 69 | // return ""; 70 | // } 71 | // } 72 | // } 73 | //} 74 | -------------------------------------------------------------------------------- /src/Log2Window/Settings/FieldType.cs: -------------------------------------------------------------------------------- 1 | // Decompiled with JetBrains decompiler 2 | // Type: Log2Window.Settings.FieldType 3 | // Assembly: Log2Window, Version=9.9.9.9, Culture=neutral, PublicKeyToken=null 4 | // MVID: 44D35A25-C349-4FB9-B272-3AC90AA136EE 5 | // Assembly location: C:\Users\rwahl\Desktop\Log2Window.exe 6 | 7 | using Log2Window.Log; 8 | using System; 9 | using System.ComponentModel; 10 | 11 | namespace Log2Window.Settings 12 | { 13 | [Serializable] 14 | public class FieldType 15 | { 16 | /// 17 | /// Gets or sets the type of field. 18 | /// 19 | /// 20 | /// The field. 21 | /// 22 | [Category("Field Configuration")] 23 | [DisplayName("Field Type")] 24 | [Description("The Type of the Field")] 25 | public LogMessageField Field { get; set; } 26 | 27 | /// 28 | /// If the Field is of type Property, specify the name of the Property 29 | /// 30 | /// 31 | /// The property. 32 | /// 33 | [Category("Field Configuration")] 34 | [DisplayName("Property")] 35 | [Description("The Name of the Property")] 36 | public string Property { get; set; } 37 | 38 | /// 39 | /// The Display / Column name of the Field 40 | /// 41 | /// 42 | /// The name of the field. 43 | /// 44 | [Category("Field Configuration")] 45 | [DisplayName("Name")] 46 | [Description("The Name of the Column")] 47 | public string Name { get; set; } 48 | 49 | public FieldType() 50 | { 51 | } 52 | 53 | public FieldType(LogMessageField field, string name, string property = null) 54 | { 55 | Field = field; 56 | Name = name; 57 | Property = property; 58 | } 59 | 60 | public override string ToString() 61 | { 62 | return String.Format("{0}, {1}",Name,Property); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Log2Window/Settings/LayoutSettings.cs: -------------------------------------------------------------------------------- 1 | // Decompiled with JetBrains decompiler 2 | // Type: Log2Window.Settings.LayoutSettings 3 | // Assembly: Log2Window, Version=9.9.9.9, Culture=neutral, PublicKeyToken=null 4 | // MVID: 44D35A25-C349-4FB9-B272-3AC90AA136EE 5 | // Assembly location: C:\Users\rwahl\Desktop\Log2Window.exe 6 | 7 | using System; 8 | using System.Drawing; 9 | using System.Windows.Forms; 10 | 11 | namespace Log2Window.Settings 12 | { 13 | [Serializable] 14 | public sealed class LayoutSettings 15 | { 16 | public Rectangle WindowPosition { get; set; } 17 | 18 | public FormWindowState WindowState { get; set; } 19 | 20 | public bool ShowLogDetailView { get; set; } 21 | 22 | public Size LogDetailViewSize { get; set; } 23 | 24 | public bool ShowLoggerTree { get; set; } 25 | 26 | public Size LoggerTreeSize { get; set; } 27 | 28 | public int[] LogListViewColumnsWidths { get; set; } 29 | 30 | public void Set(Rectangle position, FormWindowState state, Control detailView, Control loggerTree) 31 | { 32 | this.WindowPosition = position; 33 | this.WindowState = state; 34 | this.ShowLogDetailView = detailView.Visible; 35 | this.LogDetailViewSize = detailView.Size; 36 | this.ShowLoggerTree = loggerTree.Visible; 37 | this.LoggerTreeSize = loggerTree.Size; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Log2Window/Settings/ReceiversForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | 5 | using Log2Window.Receiver; 6 | 7 | 8 | namespace Log2Window.Settings 9 | { 10 | public partial class ReceiversForm : Form 11 | { 12 | public List AddedReceivers { get; protected set; } 13 | public List RemovedReceivers { get; protected set; } 14 | public List ModifiedReceivers { get; protected set; } 15 | public IReceiver SelectedReceiver { get; protected set; } 16 | 17 | public ReceiversForm(IEnumerable receivers) 18 | { 19 | AddedReceivers = new List(); 20 | RemovedReceivers = new List(); 21 | ModifiedReceivers = new List(); 22 | 23 | InitializeComponent(); 24 | removeReceiverBtn.Visible = true; 25 | this.receiverPropertyGrid.PropertyValueChanged += ReceiverPropertyGrid_PropertyValueChanged; 26 | 27 | Font = UserSettings.Instance.DefaultFont ?? Font; 28 | 29 | // Populate Receiver Types 30 | Dictionary receiverTypes = ReceiverFactory.Instance.ReceiverTypes; 31 | foreach (KeyValuePair kvp in receiverTypes) 32 | { 33 | ToolStripItem item = null; 34 | item = addReceiverCombo.DropDownItems.Add(kvp.Value.Name); 35 | 36 | if (item != null) item.Tag = kvp.Value; 37 | } 38 | 39 | // Populate Existing Receivers 40 | foreach (IReceiver receiver in receivers) 41 | AddReceiver(receiver); 42 | } 43 | 44 | private void ReceiverPropertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e) 45 | { 46 | if (!this.AddedReceivers.Contains(this.SelectedReceiver) 47 | && !this.ModifiedReceivers.Contains(this.SelectedReceiver)) 48 | { 49 | this.ModifiedReceivers.Add(this.SelectedReceiver); 50 | } 51 | } 52 | 53 | private void AddReceiver(IReceiver receiver) 54 | { 55 | string displayName = String.IsNullOrEmpty(receiver.DisplayName) 56 | ? ReceiverUtils.GetTypeDescription(receiver.GetType()) 57 | : receiver.DisplayName; 58 | ListViewItem lvi = receiversListView.Items.Add(displayName); 59 | lvi.Tag = receiver; 60 | lvi.Selected = true; 61 | } 62 | 63 | 64 | private void addReceiverCombo_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) 65 | { 66 | ReceiverFactory.ReceiverInfo info = e.ClickedItem.Tag as ReceiverFactory.ReceiverInfo; 67 | if (info != null) 68 | { 69 | // Instantiates a new receiver based on the selected type 70 | IReceiver receiver = ReceiverFactory.Instance.Create(info.Type.FullName); 71 | 72 | AddedReceivers.Add(receiver); 73 | AddReceiver(receiver); 74 | } 75 | } 76 | 77 | private void removeReceiverBtn_Click(object sender, EventArgs e) 78 | { 79 | IReceiver receiver = GetSelectedReceiver(); 80 | if (receiver == null) 81 | return; 82 | 83 | DialogResult dr = MessageBox.Show(this, "Confirm Delete?", "Confirmation", MessageBoxButtons.YesNo, 84 | MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); 85 | if (dr != DialogResult.Yes) 86 | return; 87 | 88 | receiversListView.Items.Remove(GetSelectedItem()); 89 | 90 | if (AddedReceivers.Find(r => r == receiver) != null) 91 | AddedReceivers.Remove(receiver); 92 | else if (ModifiedReceivers.Find(r => r == receiver) != null) 93 | ModifiedReceivers.Remove(receiver); 94 | else 95 | RemovedReceivers.Add(receiver); 96 | } 97 | 98 | private void receiversListView_SelectedIndexChanged(object sender, EventArgs e) 99 | { 100 | IReceiver receiver = GetSelectedReceiver(); 101 | 102 | removeReceiverBtn.Enabled = (receiver != null); 103 | receiverPropertyGrid.SelectedObject = receiver; 104 | if (receiver != null) 105 | { 106 | sampleClientConfigTextBox.Text = receiver.SampleClientConfig; 107 | SelectedReceiver = receiver; 108 | } 109 | } 110 | 111 | private ListViewItem GetSelectedItem() 112 | { 113 | if (receiversListView.SelectedItems.Count > 0) 114 | return receiversListView.SelectedItems[0]; 115 | return null; 116 | } 117 | 118 | private IReceiver GetSelectedReceiver() 119 | { 120 | if (receiversListView.SelectedItems.Count <= 0) 121 | return null; 122 | 123 | ListViewItem lvi = GetSelectedItem(); 124 | return (lvi == null) ? null : lvi.Tag as IReceiver; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Log2Window/Settings/ReceiversForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 125 | 126 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 127 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 128 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 129 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 130 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 131 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 132 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 133 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 134 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 135 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 136 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 137 | 138 | 139 | 140 | 141 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 142 | YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG 143 | YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 144 | 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw 145 | bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc 146 | VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 147 | c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 148 | Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo 149 | mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ 150 | kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D 151 | TgDQASA1MVpwzwAAAABJRU5ErkJggg== 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/Log2Window/Settings/SettingsForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Log2Window.Settings 2 | { 3 | partial class SettingsForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.cancelBtn = new System.Windows.Forms.Button(); 32 | this.okBtn = new System.Windows.Forms.Button(); 33 | this.settingsPropertyGrid = new System.Windows.Forms.PropertyGrid(); 34 | this.SuspendLayout(); 35 | // 36 | // cancelBtn 37 | // 38 | this.cancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 39 | this.cancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; 40 | this.cancelBtn.Location = new System.Drawing.Point(473, 515); 41 | this.cancelBtn.Name = "cancelBtn"; 42 | this.cancelBtn.Size = new System.Drawing.Size(75, 23); 43 | this.cancelBtn.TabIndex = 0; 44 | this.cancelBtn.Text = "Cancel"; 45 | this.cancelBtn.UseVisualStyleBackColor = true; 46 | // 47 | // okBtn 48 | // 49 | this.okBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 50 | this.okBtn.DialogResult = System.Windows.Forms.DialogResult.OK; 51 | this.okBtn.Location = new System.Drawing.Point(392, 515); 52 | this.okBtn.Name = "okBtn"; 53 | this.okBtn.Size = new System.Drawing.Size(75, 23); 54 | this.okBtn.TabIndex = 0; 55 | this.okBtn.Text = "OK"; 56 | this.okBtn.UseVisualStyleBackColor = true; 57 | // 58 | // settingsPropertyGrid 59 | // 60 | this.settingsPropertyGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 61 | | System.Windows.Forms.AnchorStyles.Left) 62 | | System.Windows.Forms.AnchorStyles.Right))); 63 | this.settingsPropertyGrid.Location = new System.Drawing.Point(12, 12); 64 | this.settingsPropertyGrid.Name = "settingsPropertyGrid"; 65 | this.settingsPropertyGrid.Size = new System.Drawing.Size(536, 497); 66 | this.settingsPropertyGrid.TabIndex = 1; 67 | this.settingsPropertyGrid.ToolbarVisible = false; 68 | // 69 | // SettingsForm 70 | // 71 | this.AcceptButton = this.okBtn; 72 | this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); 73 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 74 | this.CancelButton = this.cancelBtn; 75 | this.ClientSize = new System.Drawing.Size(560, 550); 76 | this.Controls.Add(this.settingsPropertyGrid); 77 | this.Controls.Add(this.okBtn); 78 | this.Controls.Add(this.cancelBtn); 79 | this.Name = "SettingsForm"; 80 | this.ShowInTaskbar = false; 81 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show; 82 | this.Text = "Log2Window Settings"; 83 | this.ResumeLayout(false); 84 | 85 | } 86 | 87 | #endregion 88 | 89 | private System.Windows.Forms.Button cancelBtn; 90 | private System.Windows.Forms.Button okBtn; 91 | private System.Windows.Forms.PropertyGrid settingsPropertyGrid; 92 | } 93 | } -------------------------------------------------------------------------------- /src/Log2Window/Settings/SettingsForm.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | 4 | namespace Log2Window.Settings 5 | { 6 | public partial class SettingsForm : Form 7 | { 8 | public SettingsForm(UserSettings userSettings) 9 | { 10 | InitializeComponent(); 11 | 12 | Font = UserSettings.Instance.DefaultFont ?? Font; 13 | 14 | // UI Settings 15 | UserSettings = userSettings; 16 | } 17 | 18 | public UserSettings UserSettings 19 | { 20 | get { return settingsPropertyGrid.SelectedObject as UserSettings; } 21 | set 22 | { 23 | settingsPropertyGrid.SelectedObject = value; 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Log2Window/Settings/SettingsForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /src/Log2Window/Settings/SourceFileLocation.cs: -------------------------------------------------------------------------------- 1 | // Decompiled with JetBrains decompiler 2 | // Type: Log2Window.Settings.SourceFileLocation 3 | // Assembly: Log2Window, Version=9.9.9.9, Culture=neutral, PublicKeyToken=null 4 | // MVID: 44D35A25-C349-4FB9-B272-3AC90AA136EE 5 | // Assembly location: C:\Users\rwahl\Desktop\Log2Window.exe 6 | 7 | using System; 8 | using System.ComponentModel; 9 | 10 | namespace Log2Window.Settings 11 | { 12 | [Serializable] 13 | public class SourceFileLocation 14 | { 15 | [DisplayName("Log File Source Code Path")] 16 | [Description("The Base Path of the Source Code in the Log File")] 17 | [Category("Source Location Mapping")] 18 | public string LogSource { get; set; } 19 | 20 | [Description("The Base Path of the Source Code on the Local Computer")] 21 | [Category("Source Location Mapping")] 22 | [DisplayName("Local Source Code Path")] 23 | public string LocalSource { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Log2Window/Settings/UserSettings.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/Settings/UserSettings.cs -------------------------------------------------------------------------------- /src/Log2Window/UI/AutoWaitCursor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows.Forms; 4 | 5 | 6 | namespace Log2Window.UI 7 | { 8 | /// 9 | /// Auto Wait Cursor utility class. 10 | /// Usage: 11 | /// using (new AutoWaitCursor()) 12 | /// { ...long task... } 13 | /// 14 | public sealed class AutoWaitCursor : IDisposable 15 | { 16 | public AutoWaitCursor() 17 | { 18 | Enabled = true; 19 | } 20 | 21 | public void Dispose() 22 | { 23 | Enabled = false; 24 | } 25 | 26 | public static bool Enabled 27 | { 28 | get { return Application.UseWaitCursor; } 29 | set 30 | { 31 | if (value == Application.UseWaitCursor) return; 32 | Application.UseWaitCursor = value; 33 | 34 | var f = Form.ActiveForm; 35 | if (f != null && f.Visible && f.Handle != IntPtr.Zero) // Send WM_SETCURSOR 36 | SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); 37 | } 38 | } 39 | 40 | [DllImport("user32.dll")] 41 | private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Log2Window/UI/ControlExtenders/DockExtender.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007 Herre Kuijpers - 2 | // 3 | // This source file(s) may be redistributed, altered and customized 4 | // by any means PROVIDING the authors name and all copyright 5 | // notices remain intact. 6 | // THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 7 | // EXPRESS OR IMPLIED. USE IT AT YOUR OWN RISK. THE AUTHOR ACCEPTS NO 8 | // LIABILITY FOR ANY DATA DAMAGE/LOSS THAT THIS PRODUCT MAY CAUSE. 9 | //----------------------------------------------------------------------- 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Windows.Forms; 13 | using System.Drawing; 14 | 15 | namespace ControlExtenders 16 | { 17 | internal struct DockState 18 | { 19 | /// 20 | /// the docking control (usually a container class, e.g Panel) 21 | /// 22 | public ScrollableControl Container; 23 | /// 24 | /// handle of the container that the user can use to select and move the container 25 | /// 26 | public Control Handle; 27 | 28 | /// 29 | /// splitter that is attached to this panel for resizing. 30 | /// this is optional 31 | /// 32 | public Splitter Splitter; 33 | 34 | /// 35 | /// the parent of the container 36 | /// 37 | public Control OrgDockingParent; 38 | 39 | /// 40 | /// the base docking host that contains all docking panels 41 | /// 42 | public Control OrgDockHost; 43 | 44 | /// 45 | /// the origional docking style, stored in order to reset the state 46 | /// 47 | public DockStyle OrgDockStyle; 48 | 49 | /// 50 | /// the origional bounds of the container 51 | /// 52 | public Rectangle OrgBounds; 53 | 54 | } 55 | 56 | public sealed class DockExtender 57 | { 58 | private Control _dockHost; 59 | private Floaties _floaties; 60 | 61 | // this is the blue overlay that presents a preview how the control will be docked 62 | internal Overlay Overlay = new Overlay(); 63 | 64 | 65 | public Floaties Floaties 66 | { 67 | get { return _floaties; } 68 | } 69 | 70 | public DockExtender(Control dockHost) 71 | { 72 | _dockHost = dockHost; 73 | _floaties = new Floaties(); 74 | } 75 | 76 | /// 77 | /// display the container control that is either floating or docked 78 | /// 79 | /// 80 | public void Show(Control container) 81 | { 82 | IFloaty f = _floaties.Find(container); 83 | if (f != null) f.Show(); 84 | } 85 | 86 | /// 87 | /// this will gracefully hide the container control 88 | /// making sure that the floating window is also closed 89 | /// 90 | /// 91 | public void Hide(Control container) 92 | { 93 | IFloaty f = _floaties.Find(container); 94 | if (f != null) f.Hide(); 95 | } 96 | 97 | /// 98 | /// Attach a container control and use it as a grip hande. The container must support mouse move events. 99 | /// 100 | /// container to make dockable/floatable 101 | /// the floaty that manages the container's behaviour 102 | public IFloaty Attach(ScrollableControl container) 103 | { 104 | return Attach(container, container, null); 105 | } 106 | 107 | /// 108 | /// Attach a container and a grip handle. The handle must support mouse move events. 109 | /// 110 | /// container to make dockable/floatable 111 | /// grip handle used to drag the container 112 | /// the floaty that manages the container's behaviour 113 | public IFloaty Attach(ScrollableControl container, Control handle) 114 | { 115 | return Attach(container, handle, null); 116 | } 117 | 118 | /// 119 | /// attach this class to any dockable type of container control 120 | /// to make it dockable. 121 | /// Attach a container control and use it as a grip hande. The handle must support mouse move events. 122 | /// Supply a splitter control to allow resizing of the docked container 123 | /// 124 | /// control to be dockable 125 | /// handle to be used to track the mouse movement (e.g. caption of the container) 126 | /// splitter to resize the docked container (optional) 127 | public IFloaty Attach(ScrollableControl container, Control handle, Splitter splitter) 128 | { 129 | if (container == null) throw new ArgumentException("container cannot be null"); 130 | if (handle == null) throw new ArgumentException("handle cannot be null"); 131 | 132 | DockState _dockState = new DockState(); 133 | _dockState.Container = container; 134 | _dockState.Handle = handle; 135 | _dockState.OrgDockHost = _dockHost; 136 | _dockState.Splitter = splitter; 137 | 138 | Floaty floaty = new Floaty(this); 139 | floaty.Attach(_dockState); 140 | _floaties.Add(floaty); 141 | return floaty; 142 | } 143 | 144 | // finds the potential dockhost control at the specified location 145 | internal Control FindDockHost(Floaty floaty , Point pt) 146 | { 147 | Control c = null; 148 | if (FormIsHit(floaty.DockState.OrgDockHost, pt)) 149 | c = floaty.DockState.OrgDockHost; //assume toplevel control 150 | 151 | if (floaty.DockOnHostOnly) 152 | return c; 153 | 154 | foreach (Floaty f in Floaties) 155 | { 156 | if (f.DockState.Container.Visible && FormIsHit(f.DockState.Container, pt)) 157 | { 158 | // add this line to dissallow docking inside floaties 159 | //if (f.Visible) continue; 160 | 161 | c = f.DockState.Container; // found suitable floating form 162 | break; 163 | } 164 | } 165 | return c; 166 | } 167 | 168 | // finds the potential dockhost control at the specified location 169 | internal bool FormIsHit(Control c, Point pt) 170 | { 171 | if (c == null) return false; 172 | 173 | Point pc = c.PointToClient(pt); 174 | bool hit = c.ClientRectangle.IntersectsWith(new Rectangle(pc, new Size(1, 1))); //.TopLevelControl; // this is tricky 175 | return hit; 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/Log2Window/UI/ControlExtenders/Overlay.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2007 Herre Kuijpers - 2 | // 3 | // This source file(s) may be redistributed, altered and customized 4 | // by any means PROVIDING the authors name and all copyright 5 | // notices remain intact. 6 | // THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 7 | // EXPRESS OR IMPLIED. USE IT AT YOUR OWN RISK. THE AUTHOR ACCEPTS NO 8 | // LIABILITY FOR ANY DATA DAMAGE/LOSS THAT THIS PRODUCT MAY CAUSE. 9 | //----------------------------------------------------------------------- 10 | using System; 11 | using System.Collections.Generic; 12 | using System.ComponentModel; 13 | using System.Text; 14 | using System.Windows.Forms; 15 | 16 | namespace ControlExtenders 17 | { 18 | /// 19 | /// this is the overlay preview control 20 | /// 21 | internal sealed class Overlay : Form 22 | { 23 | public Overlay() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | // override Dockstate. 29 | public new DockStyle Dock; 30 | public Control DockHostControl; 31 | 32 | /// 33 | /// Required designer variable. 34 | /// 35 | private IContainer components = null; 36 | 37 | /// 38 | /// Clean up any resources being used. 39 | /// 40 | /// true if managed resources should be disposed; otherwise, false. 41 | protected override void Dispose(bool disposing) 42 | { 43 | if (disposing && (components != null)) 44 | { 45 | components.Dispose(); 46 | } 47 | base.Dispose(disposing); 48 | } 49 | 50 | #region Windows Form Designer generated code 51 | 52 | /// 53 | /// Required method for Designer support - do not modify 54 | /// the contents of this method with the code editor. 55 | /// 56 | private void InitializeComponent() 57 | { 58 | this.SuspendLayout(); 59 | // 60 | // Overlay 61 | // 62 | this.BackColor = System.Drawing.SystemColors.ActiveCaption; 63 | this.ControlBox = false; 64 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 65 | this.MaximizeBox = false; 66 | this.MinimizeBox = false; 67 | this.Name = "Overlay"; 68 | this.Opacity = 0.3; 69 | this.ShowIcon = false; 70 | this.ShowInTaskbar = false; 71 | this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; 72 | this.Text = "Overlay"; 73 | this.ResumeLayout(false); 74 | } 75 | 76 | #endregion 77 | } 78 | } -------------------------------------------------------------------------------- /src/Log2Window/UI/FlickerFreeListView.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | 4 | namespace Log2Window.UI 5 | { 6 | class FlickerFreeListView : ListView 7 | { 8 | public FlickerFreeListView() 9 | { 10 | // Activate double buffering 11 | SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.CacheText, true); 12 | 13 | // Enable the OnNotifyMessage event so we get a chance to filter out 14 | // Windows messages before they get to the form's WndProc 15 | SetStyle(ControlStyles.EnableNotifyMessage, false); 16 | } 17 | 18 | protected override void OnNotifyMessage(Message m) 19 | { 20 | // Filter out the WM_ERASEBKGND message 21 | if (m.Msg != 0x14) 22 | { 23 | base.OnNotifyMessage(m); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Log2Window/UI/ToolStripControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | 6 | namespace Log2Window.UI 7 | { 8 | public class ToolStripControl : ToolStripControlHost 9 | where T : Control, new() 10 | { 11 | public ToolStripControl() : base(new T()) 12 | { 13 | } 14 | 15 | public T CoreControl 16 | { 17 | get 18 | { 19 | return Control as T; 20 | } 21 | } 22 | 23 | /* 24 | public override Size GetPreferredSize(Size constrainingSize) 25 | { 26 | // Use the default size if the text box is on the overflow menu 27 | // or is on a vertical ToolStrip. 28 | if (IsOnOverflow || Owner.Orientation == Orientation.Vertical) 29 | { 30 | return DefaultSize; 31 | } 32 | 33 | // Declare a variable to store the total available width as 34 | // it is calculated, starting with the display width of the 35 | // owning ToolStrip. 36 | Int32 width = Owner.DisplayRectangle.Width; 37 | 38 | // Subtract the width of the overflow button if it is displayed. 39 | if (Owner.OverflowButton.Visible) 40 | { 41 | width = width - Owner.OverflowButton.Width - 42 | Owner.OverflowButton.Margin.Horizontal; 43 | } 44 | 45 | // Declare a variable to maintain a count of ToolStripControl 46 | // items currently displayed in the owning ToolStrip. 47 | Int32 springBoxCount = 0; 48 | 49 | foreach (ToolStripItem item in Owner.Items) 50 | { 51 | // Ignore items on the overflow menu. 52 | if (item.IsOnOverflow) continue; 53 | 54 | if (item is ToolStripControl) 55 | { 56 | // For ToolStripControl items, increment the count and 57 | // subtract the margin width from the total available width. 58 | springBoxCount++; 59 | width -= item.Margin.Horizontal; 60 | } 61 | else 62 | { 63 | // For all other items, subtract the full width from the total 64 | // available width. 65 | width = width - item.Width - item.Margin.Horizontal; 66 | } 67 | } 68 | 69 | // If there are multiple ToolStripControl items in the owning 70 | // ToolStrip, divide the total available width between them. 71 | if (springBoxCount > 1) width /= springBoxCount; 72 | 73 | // If the available width is less than the default width, use the 74 | // default width, forcing one or more items onto the overflow menu. 75 | if (width < DefaultSize.Width) width = DefaultSize.Width; 76 | 77 | // Retrieve the preferred size from the base class, but change the 78 | // width to the calculated width. 79 | Size size = base.GetPreferredSize(constrainingSize); 80 | size.Width = width; 81 | return size; 82 | } 83 | */ 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Log2Window/UI/TreeViewLoggerView.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/UI/TreeViewLoggerView.cs -------------------------------------------------------------------------------- /src/Log2Window/UI/TreeViewWithoutDoubleClick.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace Log2Window.UI 8 | { 9 | //fix bug of treeview with checkbox. 10 | //http://stackoverflow.com/questions/17356976/treeview-with-checkboxes-not-processing-clicks-correctly 11 | class TreeViewWithoutDoubleClick : TreeView 12 | { 13 | protected override void WndProc(ref Message m) 14 | { 15 | if (m.Msg == 0x203) // identified double click 16 | { 17 | var localPos = PointToClient(Cursor.Position); 18 | var hitTestInfo = HitTest(localPos); 19 | if (hitTestInfo.Location == TreeViewHitTestLocations.StateImage) 20 | m.Result = IntPtr.Zero; 21 | else 22 | base.WndProc(ref m); 23 | } 24 | else base.WndProc(ref m); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/Log2Window/Utils.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/Utils.cs -------------------------------------------------------------------------------- /src/Log2Window/res/Excel.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/Excel.ico -------------------------------------------------------------------------------- /src/Log2Window/res/Go16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/Go16.png -------------------------------------------------------------------------------- /src/Log2Window/res/Pause16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/Pause16.png -------------------------------------------------------------------------------- /src/Log2Window/res/back16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/back16.png -------------------------------------------------------------------------------- /src/Log2Window/res/backward16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/backward16.png -------------------------------------------------------------------------------- /src/Log2Window/res/burn16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/burn16.png -------------------------------------------------------------------------------- /src/Log2Window/res/cd16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/cd16.png -------------------------------------------------------------------------------- /src/Log2Window/res/close16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/close16.png -------------------------------------------------------------------------------- /src/Log2Window/res/collapse_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/collapse_all.png -------------------------------------------------------------------------------- /src/Log2Window/res/configure16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/configure16.png -------------------------------------------------------------------------------- /src/Log2Window/res/delete16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/delete16.png -------------------------------------------------------------------------------- /src/Log2Window/res/deletefile16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/deletefile16.png -------------------------------------------------------------------------------- /src/Log2Window/res/documentsorcopy16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/documentsorcopy16.png -------------------------------------------------------------------------------- /src/Log2Window/res/eventLog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/eventLog.png -------------------------------------------------------------------------------- /src/Log2Window/res/find16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/find16.png -------------------------------------------------------------------------------- /src/Log2Window/res/forward16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/forward16.png -------------------------------------------------------------------------------- /src/Log2Window/res/gotoapp16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/gotoapp16.png -------------------------------------------------------------------------------- /src/Log2Window/res/infoabout16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/infoabout16.png -------------------------------------------------------------------------------- /src/Log2Window/res/movefile16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/movefile16.png -------------------------------------------------------------------------------- /src/Log2Window/res/next16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/next16.png -------------------------------------------------------------------------------- /src/Log2Window/res/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/pin.png -------------------------------------------------------------------------------- /src/Log2Window/res/receive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/receive.png -------------------------------------------------------------------------------- /src/Log2Window/res/saveas16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/saveas16.png -------------------------------------------------------------------------------- /src/Log2Window/res/unselect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/unselect.png -------------------------------------------------------------------------------- /src/Log2Window/res/window16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/window16.png -------------------------------------------------------------------------------- /src/Log2Window/res/windowb.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/windowb.ico -------------------------------------------------------------------------------- /src/Log2Window/res/zoomin16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/zoomin16.png -------------------------------------------------------------------------------- /src/Log2Window/res/zoomout16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/Log2Window/res/zoomout16.png -------------------------------------------------------------------------------- /src/TestLog4net/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/TestLog4net/Config/log4net.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /src/TestLog4net/MsmqAppender.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/TestLog4net/MsmqAppender.cs -------------------------------------------------------------------------------- /src/TestLog4net/MyXmlLayoutSchemaLog4j.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Xml; 6 | using log4net.Core; 7 | using log4net.Util; 8 | 9 | namespace AlanThinker.MyLog4net 10 | { 11 | /// 12 | /// SimpleXmlLayoutSchemaLog4j which without hostname, appdomain name, identity name, user name, ndcObj and properties. 13 | /// So have better performance. 14 | /// 15 | class MyXmlLayoutSchemaLog4j : log4net.Layout.XmlLayoutSchemaLog4j 16 | { 17 | private static readonly DateTime s_date1970 = new DateTime(1970, 1, 1); 18 | 19 | #region Some switch which can cause performance issue. 20 | 21 | public bool Show_Hostname_Appdomain_Identity_UserName { get; set; } 22 | public bool ShowNDC { get; set; } 23 | public bool ShowProperties { get; set; } 24 | //设置logName的命名空间前缀, 这样log2window收到多个来源的日志, 就可以很方便的通过前缀来区分了. 25 | public string NamespacePrefix { get; set; } 26 | 27 | #endregion 28 | 29 | protected override void FormatXml(XmlWriter writer, LoggingEvent loggingEvent) 30 | { 31 | //// Translate logging events for log4j 32 | 33 | if (this.Show_Hostname_Appdomain_Identity_UserName) 34 | { 35 | // Translate hostname property 36 | if (loggingEvent.LookupProperty(LoggingEvent.HostNameProperty) != null && 37 | loggingEvent.LookupProperty("log4jmachinename") == null) 38 | { 39 | loggingEvent.GetProperties()["log4jmachinename"] = loggingEvent.LookupProperty(LoggingEvent.HostNameProperty); 40 | } 41 | 42 | // translate appdomain name 43 | if (loggingEvent.LookupProperty("log4japp") == null && 44 | loggingEvent.Domain != null && 45 | loggingEvent.Domain.Length > 0) 46 | { 47 | loggingEvent.GetProperties()["log4japp"] = loggingEvent.Domain; 48 | } 49 | 50 | // translate identity name 51 | if (loggingEvent.Identity != null && 52 | loggingEvent.Identity.Length > 0 && 53 | loggingEvent.LookupProperty(LoggingEvent.IdentityProperty) == null) 54 | { 55 | loggingEvent.GetProperties()[LoggingEvent.IdentityProperty] = loggingEvent.Identity; 56 | } 57 | 58 | // translate user name 59 | if (loggingEvent.UserName != null && 60 | loggingEvent.UserName.Length > 0 && 61 | loggingEvent.LookupProperty(LoggingEvent.UserNameProperty) == null) 62 | { 63 | loggingEvent.GetProperties()[LoggingEvent.UserNameProperty] = loggingEvent.UserName; 64 | } 65 | } 66 | 67 | // Write the start element 68 | writer.WriteStartElement("log4j:event"); 69 | var newLogName = loggingEvent.LoggerName; 70 | if (!string.IsNullOrEmpty(NamespacePrefix)) 71 | { 72 | newLogName = NamespacePrefix + "." + newLogName; 73 | } 74 | writer.WriteAttributeString("logger", newLogName); 75 | 76 | // Calculate the timestamp as the number of milliseconds since january 1970 77 | // 78 | // We must convert the TimeStamp to UTC before performing any mathematical 79 | // operations. This allows use to take into account discontinuities 80 | // caused by daylight savings time transitions. 81 | TimeSpan timeSince1970 = loggingEvent.TimeStamp.ToUniversalTime() - s_date1970; 82 | 83 | writer.WriteAttributeString("timestamp", XmlConvert.ToString((long)timeSince1970.TotalMilliseconds)); 84 | writer.WriteAttributeString("level", loggingEvent.Level.DisplayName); 85 | writer.WriteAttributeString("thread", loggingEvent.ThreadName); 86 | 87 | // Append the message text 88 | writer.WriteStartElement("log4j:message"); 89 | Transform.WriteEscapedXmlString(writer, loggingEvent.RenderedMessage, this.InvalidCharReplacement); 90 | writer.WriteEndElement(); 91 | 92 | if (this.ShowNDC) 93 | { 94 | object ndcObj = loggingEvent.LookupProperty("NDC"); 95 | if (ndcObj != null) 96 | { 97 | string valueStr = loggingEvent.Repository.RendererMap.FindAndRender(ndcObj); 98 | 99 | if (valueStr != null && valueStr.Length > 0) 100 | { 101 | // Append the NDC text 102 | writer.WriteStartElement("log4j:NDC"); 103 | Transform.WriteEscapedXmlString(writer, valueStr, this.InvalidCharReplacement); 104 | writer.WriteEndElement(); 105 | } 106 | } 107 | } 108 | 109 | // Append the properties text 110 | 111 | if (this.ShowProperties) 112 | { 113 | PropertiesDictionary properties = loggingEvent.GetProperties(); 114 | if (properties.Count > 0) 115 | { 116 | writer.WriteStartElement("log4j:properties"); 117 | foreach (System.Collections.DictionaryEntry entry in properties) 118 | { 119 | writer.WriteStartElement("log4j:data"); 120 | writer.WriteAttributeString("name", (string)entry.Key); 121 | 122 | // Use an ObjectRenderer to convert the object to a string 123 | string valueStr = loggingEvent.Repository.RendererMap.FindAndRender(entry.Value); 124 | writer.WriteAttributeString("value", valueStr); 125 | 126 | writer.WriteEndElement(); 127 | } 128 | writer.WriteEndElement(); 129 | } 130 | } 131 | 132 | string exceptionStr = loggingEvent.GetExceptionString(); 133 | if (exceptionStr != null && exceptionStr.Length > 0) 134 | { 135 | // Append the stack trace line 136 | writer.WriteStartElement("log4j:throwable"); 137 | Transform.WriteEscapedXmlString(writer, exceptionStr, this.InvalidCharReplacement); 138 | writer.WriteEndElement(); 139 | } 140 | 141 | if (LocationInfo) 142 | { 143 | LocationInfo locationInfo = loggingEvent.LocationInformation; 144 | 145 | writer.WriteStartElement("log4j:locationInfo"); 146 | writer.WriteAttributeString("class", locationInfo.ClassName); 147 | writer.WriteAttributeString("method", locationInfo.MethodName); 148 | writer.WriteAttributeString("file", locationInfo.FileName); 149 | writer.WriteAttributeString("line", locationInfo.LineNumber); 150 | writer.WriteEndElement(); 151 | } 152 | 153 | writer.WriteEndElement(); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/TestLog4net/Program.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alanthinker/Log2Window/f40235b8979b92d8438f768d870f8e7645e4a6bb/src/TestLog4net/Program.cs -------------------------------------------------------------------------------- /src/TestLog4net/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Test")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Test")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7bf73781-a136-488c-8984-a3b60d361846")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /src/TestLog4net/TestLog4net.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.30729 7 | 2.0 8 | {29A745D4-5A2F-4170-A0F1-54C77F151892} 9 | Exe 10 | Properties 11 | Test 12 | Test 13 | . 14 | https://tfs.codeplex.com/tfs/tfs04 15 | {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} 16 | 17 | 18 | 3.5 19 | 20 | 21 | v4.5.1 22 | publish\ 23 | true 24 | Disk 25 | false 26 | Foreground 27 | 7 28 | Days 29 | false 30 | false 31 | true 32 | 0 33 | 1.0.0.%2a 34 | false 35 | false 36 | true 37 | 38 | 39 | 40 | true 41 | full 42 | false 43 | bin\Debug\ 44 | TRACE;DEBUG 45 | prompt 46 | 4 47 | AllRules.ruleset 48 | true 49 | false 50 | 51 | 52 | pdbonly 53 | true 54 | bin\Release\ 55 | TRACE 56 | prompt 57 | 4 58 | AllRules.ruleset 59 | false 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | Designer 77 | 78 | 79 | Always 80 | Designer 81 | 82 | 83 | 84 | 85 | False 86 | .NET Framework 3.5 SP1 Client Profile 87 | false 88 | 89 | 90 | False 91 | .NET Framework 3.5 SP1 92 | true 93 | 94 | 95 | False 96 | Windows Installer 3.1 97 | true 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 2.0.10 106 | 107 | 108 | 109 | 116 | -------------------------------------------------------------------------------- /src/TestNLog/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/TestNLog/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NLog; 3 | using TestNLog.Company.Product.BusinessLogic; 4 | using TestNLog.Company.Product.ServiceTester; 5 | namespace TestNLog 6 | { 7 | class Program 8 | { 9 | static readonly Logger _log = LogManager.GetCurrentClassLogger(); 10 | 11 | static void Main(string[] args) 12 | { 13 | ////if (!EventLog.SourceExists("log4net")) 14 | ////{ 15 | //// //An event log source should not be created and immediately used. 16 | //// //There is a latency time to enable the source, it should be created 17 | //// //prior to executing the application that uses the source. 18 | //// //Execute this sample a second time to use the new source. 19 | //// EventLog.CreateEventSource("log4net", "Application"); 20 | ////} 21 | 22 | ConsoleKeyInfo key = new ConsoleKeyInfo(); 23 | while (key.Key != ConsoleKey.X) 24 | { 25 | 26 | DoLog(key.KeyChar); 27 | 28 | 29 | DoWinDebug(); 30 | key = Console.ReadKey(); 31 | } 32 | } 33 | 34 | static void DoWinDebug() 35 | { 36 | //Console.WriteLine("Begin Doing WinDebug!"); 37 | //System.Diagnostics.Debug.WriteLine("This is a call to System.Diagnostics.Debug"); 38 | //System.Diagnostics.Trace.WriteLine("This is a call to System.Diagnostics.Trace"); 39 | //Console.WriteLine("End Doing WinDebug!"); 40 | } 41 | 42 | static void DoLog(char keyChar) 43 | { 44 | Console.WriteLine("\nBegin Doing Log!"); 45 | Console.WriteLine(DateTime.Now); 46 | if (Char.ToLower(keyChar) == 'b') 47 | { 48 | for (int i = 0; i < 10000; i++) 49 | { 50 | _log.Info(i); 51 | } 52 | } 53 | else if (keyChar >= '1' && keyChar <= '9') 54 | { 55 | _log.Info(keyChar); 56 | } 57 | else if (Char.ToLower(keyChar) == 'e') 58 | { 59 | try 60 | { 61 | ThrowTestEx(); 62 | return; 63 | } 64 | catch (Exception ex) 65 | { 66 | _log.Error("TestEx", ex); 67 | } 68 | } 69 | else if (Char.ToLower(keyChar) == 'c') 70 | { 71 | for (int i = 0; i < 10; i++) 72 | { 73 | _log.Info("测试中文"); 74 | } 75 | } 76 | else 77 | { 78 | if (_log.IsErrorEnabled) 79 | _log.Error("This is an Error..."); 80 | 81 | if (_log.IsDebugEnabled) 82 | for (int i = 0; i < 10; i++) 83 | _log.Debug("This is a simple log!"); 84 | 85 | if (_log.IsErrorEnabled) 86 | _log.Error("This is an Error..."); 87 | 88 | if (_log.IsInfoEnabled) 89 | _log.Info("This is an Info..."); 90 | 91 | 92 | _log.Warn("This is a Warning..."); 93 | _log.Fatal("This is a Fatal..."); 94 | 95 | _log.Error("This is an error with an exception.", new Exception("The message exception here.")); 96 | 97 | _log.Warn("This is a message on many lines...\nlines...\nlines...\nlines..."); 98 | _log.Warn("This is a message on many lines...\r\nlines...\r\nlines...\r\nlines..."); 99 | 100 | DummyManager dm = new DummyManager(); 101 | dm.DoIt(); 102 | 103 | DummyTester dt = new DummyTester(); 104 | dt.DoIt(); 105 | } 106 | 107 | Console.WriteLine("End Doing Log!"); 108 | } 109 | 110 | private static void ThrowTestEx() 111 | { 112 | throw new Exception("TestEx"); 113 | } 114 | 115 | } 116 | 117 | namespace Company.Product.BusinessLogic 118 | { 119 | 120 | public class DummyManager 121 | { 122 | public static readonly Logger Log = LogManager.GetCurrentClassLogger(); 123 | 124 | 125 | public DummyManager() 126 | { 127 | if (Log.IsInfoEnabled) 128 | Log.Info("Dummy Manager ctor"); 129 | } 130 | 131 | public void DoIt() 132 | { 133 | if (Log.IsDebugEnabled) 134 | Log.Debug("DM: Do It, Do It Now!!"); 135 | 136 | Log.Warn("This is a Warning from DM..."); 137 | Log.Error("This is an Error from DM..."); 138 | Log.Fatal("This is a Fatal from DM..."); 139 | 140 | Log.ErrorException("This is an error from DM with an exception.", new Exception("The message exception here.")); 141 | } 142 | } 143 | } 144 | 145 | namespace Company.Product.ServiceTester 146 | { 147 | 148 | public class DummyTester 149 | { 150 | public static readonly Logger Log = LogManager.GetCurrentClassLogger(); 151 | 152 | public DummyTester() 153 | { 154 | if (Log.IsInfoEnabled) 155 | Log.Info("Dummy Tester ctor"); 156 | } 157 | 158 | public void DoIt() 159 | { 160 | if (Log.IsDebugEnabled) 161 | Log.Debug("DT: Do It, Do It Now!!"); 162 | 163 | Log.Warn("This is a Warning from DT..."); 164 | Log.Error("This is an Error from DT..."); 165 | Log.Fatal("This is a Fatal from DT..."); 166 | 167 | Log.ErrorException("This is an error from DT with an exception.", new Exception("The message exception here.")); 168 | } 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/TestNLog/TestNLog.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {7C4E8E11-81E3-4297-A4D9-6F6DB90C8EF7} 9 | Exe 10 | Properties 11 | TestNLog 12 | TestNLog 13 | v4.5.1 14 | 15 | 16 | 512 17 | 18 | 19 | true 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | full 23 | AnyCPU 24 | bin\Debug\TestNLog.exe.CodeAnalysisLog.xml 25 | true 26 | GlobalSuppressions.cs 27 | prompt 28 | MinimumRecommendedRules.ruleset 29 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 30 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 31 | true 32 | false 33 | 34 | 35 | bin\Release\ 36 | TRACE 37 | true 38 | pdbonly 39 | AnyCPU 40 | bin\Release\TestNLog.exe.CodeAnalysisLog.xml 41 | true 42 | GlobalSuppressions.cs 43 | prompt 44 | MinimumRecommendedRules.ruleset 45 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets 46 | true 47 | ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules 48 | true 49 | false 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | PreserveNewest 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 4.3.10 69 | 70 | 71 | 72 | 79 | -------------------------------------------------------------------------------- /src/TestNLog/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/script_Publish.sh: -------------------------------------------------------------------------------- 1 | 2 | ####################### 引用common ####################### 3 | source "/mnt/d/Projects/XxcProjects/ShellScript/common.sh" 4 | 5 | ####################### 初始化 ####################### 6 | # 当前目录被定义在 $startScriptDir 中 7 | alanInit 8 | mydir=$startScriptDir 9 | 10 | ####################### ####################### 11 | readVarFromNT msbuild 12 | toBashPath msbuild 13 | "$msbuild" 14 | 15 | if [ "$msbuild" == "" ] ; then 16 | showErrorAndExit "系统环境变量msbuild必须设置到MSBuild.exe的路径" 17 | fi 18 | 19 | rm -rf /mnt/d/temp/Log2Window 20 | checkIfActionError "清空目录出错 $LINENO" 21 | rm -f /mnt/d/temp/Log2Window.zip 22 | checkIfActionError "删除文件出错 $LINENO" 23 | 24 | mkdir -p /mnt/d/temp/Log2Window 25 | mkdir -p /mnt/d/temp/Log2Window/ExampleProject 26 | "$msbuild" \ 27 | /t:rebuild \ 28 | /property:OutputPath=d:/temp/Log2Window \ 29 | /property:Configuration=Release \ 30 | /property:DeployOnBuild=true \ 31 | "Log2Window\Log2Window.csproj" 32 | checkIfActionError "编译出错" 33 | 34 | cp -rf TestLog4net /mnt/d/temp/Log2Window/ExampleProject 35 | checkIfActionError "出错 $LINENO" 36 | cp -rf TestNLog /mnt/d/temp/Log2Window/ExampleProject 37 | checkIfActionError "出错 $LINENO" 38 | 39 | find /mnt/d/temp/Log2Window/ExampleProject -name "bin" -exec rm -rf {} \; 40 | find /mnt/d/temp/Log2Window/ExampleProject -name "obj" -exec rm -rf {} \; 41 | find /mnt/d/temp/Log2Window/ExampleProject -name "packages" -exec rm -rf {} \; 42 | 43 | mkdir /mnt/d/temp/Log2Window/bin 44 | mv /mnt/d/temp/Log2Window/*.dll /mnt/d/temp/Log2Window/bin 45 | mv /mnt/d/temp/Log2Window/*.xml /mnt/d/temp/Log2Window/bin 46 | 47 | cd /mnt/d/temp 48 | zip -r Log2Window.zip Log2Window 49 | checkIfActionError "压缩出错" 50 | cp -af /mnt/d/temp/Log2Window/. "/mnt/d/Users/Alan/Documents/YunPan/Program Files/Log2Window" 51 | cp -f "/mnt/d/Temp/Log2Window.zip" "/mnt/d/Users/Alan/Documents/YunPan/Program Files" 52 | checkIfActionError "出错 $LINENO" 53 | showInfo 全部完成. 54 | 55 | read temp --------------------------------------------------------------------------------