#define XDateTimeAxis using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Linq; using System.Windows.Forms; using DDUtilityApp.LOGPARSER.DATA; using JWH; using JWH.DATA; using Telerik.Charting; using Telerik.WinControls.UI; namespace DDUtilityApp.LOGPARSER { public partial class FrmMessageReplyTime1 : Form { #region [ Deleage ] =================================================== #endregion #region [ Events ] ==================================================== #endregion #region [ Variables ] ================================================= private Dictionary AnalysisCollection = new Dictionary(); private CartesianAxis HorizontalAxis { get; set; } = null; private LinearAxis VerticalAxis { get; set; } = null; #endregion #region [ Properties ] ================================================ public StandardCollection StandardCollection { get; set; } = null; public Dictionary> MessageCollection { get; set; } = new Dictionary>(); public RadGridView GridView { get; set; } = null; #endregion #region [ Constructor ] =============================================== public FrmMessageReplyTime1() { InitializeComponent(); this.SetLayout(); this.SetEventHandler(); } public FrmMessageReplyTime1(StandardCollection standardCollection) : this() { this.StandardCollection = standardCollection; } private void SetLayout() { Font font = new Font("돋움체", 9); this.cboxMessageName.Font = font; this.Grid_Setting(); this.GridAnalysis_Setting(); this.Chart_Setting(); } private void SetEventHandler() { this.btnGenerate.Click += this.BtnGenerate_Click; this.chkTrimmed.CheckedChanged += this.ChkTrimmed_CheckedChanged; this.button1.Click += this.Button1_Click; this.cboxMessageName.SelectedIndexChanged += this.CboxMessageName_SelectedIndexChanged; this.chkShowLabel.CheckedChanged += this.ChkShowLabel_CheckedChanged; ChartTrackballController controller = new ChartTrackballController(); controller.TextNeeded += this.ChartTrackball_TextNeeded; this.chart.Controllers.Add(controller); this.grid.RowFormatting += this.Grid_RowFormatting; this.grid.CellDoubleClick += this.Grid_CellDoubleClick; this.gridAnalysis.RowFormatting += this.GridAnalysis_RowFormatting; this.gridAnalysis.CellFormatting += this.GridAnalysis_CellFormatting; } #endregion #region [ Control Events ] ============================================ private void BtnGenerate_Click(object sender, EventArgs e) { this.Generate(); } private void ChkTrimmed_CheckedChanged(object sender, EventArgs e) { } private void CboxMessageName_SelectedIndexChanged(object sender, EventArgs e) { this.chart.Series.Clear(); try { #region Grid Display List lst = new List(); if (string.IsNullOrEmpty(this.cboxMessageName.Text)) { foreach (KeyValuePair> pair in this.MessageCollection) { lst.AddRange(pair.Value.ToArray()); this.Chart_AddSeries(pair.Key, pair.Value.ToArray()); } } else { string key = this.cboxMessageName.Text; if (this.MessageCollection.ContainsKey(key) == false) return; lst.AddRange(this.MessageCollection[key].ToArray()); this.Chart_AddSeries(key, this.MessageCollection[key].ToArray()); } this.grid.AutoBinding(lst.ToArray()); #endregion #region Chart Display if (lst.Count < 1) return; if (this.chart.Series.Count < 1) return; StandardDataPair min = lst[0]; StandardDataPair max = lst[0]; foreach (StandardDataPair pair in lst) { if (pair.RequestTime < min.RequestTime) min = pair; if (pair.RequestTime > max.RequestTime) max = pair; } foreach (CartesianAxis item in this.chart.Axes) { if (item.GetType() == typeof(DateTimeContinuousAxis)) { DateTimeContinuousAxis axis = item as DateTimeContinuousAxis; //datetimeAxis.PlotMode = AxisPlotMode.BetweenTicks; //datetimeAxis.LabelFormat = "{0:d}"; axis.MajorStepUnit = TimeInterval.Hour; axis.LabelFormatProvider = new DateTimeFormatProvider(); } else if (item.GetType() == typeof(CategoricalAxis)) { CategoricalAxis axis = item as CategoricalAxis; if (lst.Count < 10) axis.MajorTickInterval = 1; else axis.MajorTickInterval = (int)Math.Round(lst.Count / 10.0); } else if (item.GetType() == typeof(LinearAxis)) { LinearAxis axis = item as LinearAxis; } } #endregion } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } private void Button1_Click(object sender, EventArgs e) { } private void ChkShowLabel_CheckedChanged(object sender, EventArgs e) { foreach (ChartSeries series in this.chart.Series) series.ShowLabels = this.chkShowLabel.Checked; } private void ChartTrackball_TextNeeded(object sender, TextNeededEventArgs e) { StandardDataPair data = e.Points[0].DataPoint.DataItem as StandardDataPair; if (data != null) { e.Text = $"{data.RequestTime}{Environment.NewLine}{data.MessageName} : {data.Interval}"; } } private void Grid_RowFormatting(object sender, RowFormattingEventArgs e) { StandardDataPair stdPair = e.RowElement.RowInfo.DataBoundItem as StandardDataPair; if (stdPair == null) return; if (this.AnalysisCollection.ContainsKey(stdPair.MessageName) == false) return; StandardDataAnalysis stdAnalysis = this.AnalysisCollection[stdPair.MessageName]; if (stdAnalysis.CheckOver(stdPair)) e.RowElement.ForeColor = Color.Red; else e.RowElement.ForeColor = SystemColors.ControlText; } private void Grid_CellDoubleClick(object sender, GridViewCellEventArgs e) { StandardDataPair pair = e.Row.DataBoundItem as StandardDataPair; if (pair == null) return; if (this.GridView == null) return; RadGridView grid = this.GridView; try { this.Cursor = Cursors.WaitCursor; StandardData data = pair.Request; if (e.Column.FieldName.ToUpper() == "RESPONSETIME") data = pair.Response; int lineNumber = data.LineNumber; foreach (GridViewRowInfo row in grid.Rows) { try { StandardData standardData = row.DataBoundItem as StandardData; if (standardData == null) continue; if (lineNumber <= standardData.LineNumber) { this.grid.Focus(); row.IsSelected = false; row.IsCurrent = false; row.IsSelected = true; row.IsCurrent = true; break; } } catch (Exception ex) { XLogger.Instance.Debug(ex); } } } catch (Exception ex) { XLogger.Instance.Fatal(ex); } finally { this.Cursor = Cursors.Default; } } private void GridAnalysis_RowFormatting(object sender, RowFormattingEventArgs e) { } private void GridAnalysis_CellFormatting(object sender, CellFormattingEventArgs e) { string[] arrTrimmed = new string[] { "TrimmedMean", "TrimmedStdDeviation" }; string[] arrArithmetic = new string[] { "ArithmeticMean", "ArithmeticStdDeviation" }; if (this.chkTrimmed.Checked) { if (arrArithmetic.Contains(e.Column.FieldName)) e.CellElement.ForeColor = Color.LightGray; else e.CellElement.ForeColor = SystemColors.ControlText; } else { if (arrTrimmed.Contains(e.Column.FieldName)) e.CellElement.ForeColor = Color.LightGray; else e.CellElement.ForeColor = SystemColors.ControlText; } } #endregion #region [ Public Method ] ============================================= public void Generate() { this.DataGenerate(); this.DataAnalysis(); List lstMessage = new List(); lstMessage.Add(""); lstMessage.AddRange(this.MessageCollection.Keys.ToArray()); lstMessage.Sort(); this.cboxMessageName.DataSource = lstMessage.ToArray(); this.cboxMessageName.SelectedIndex = 0; } #endregion #region [ Method ] ==================================================== private void DataGenerate() { Dictionary> dicSrc = new Dictionary>(); try { this.MessageCollection.Clear(); string[] arrServer = new string[] { "MES", "FDC", "RMS", "RTD" }; foreach (StandardData data in this.StandardCollection) { if (arrServer.Contains(data.Server) == false) continue; if (string.IsNullOrWhiteSpace(data.TID)) continue; string key = data.MessageName.Replace("Reply", ""); if (dicSrc.ContainsKey(key) == false) { dicSrc.Add(key, new List()); StandardDataPair pair = dicSrc[key].Where(x => x.TID == data.TID).FirstOrDefault(); if (pair == null) dicSrc[key].Add(new StandardDataPair(data)); else pair.Add(data); } else { StandardDataPair pair = dicSrc[key].Where(x => x.TID == data.TID).FirstOrDefault(); if (pair == null) dicSrc[key].Add(new StandardDataPair(data)); else pair.Add(data); } } foreach (KeyValuePair> srcPair in dicSrc) { string key = srcPair.Key; foreach (StandardDataPair pair in srcPair.Value) { if (pair.Request == null || pair.Response == null) continue; if (this.MessageCollection.ContainsKey(key) == false) MessageCollection.Add(key, new List()); this.MessageCollection[key].Add(pair); } } } catch (Exception ex) { XLogger.Instance.Fatal(ex); } } private void DataAnalysis() { this.AnalysisCollection.Clear(); foreach (KeyValuePair> item in this.MessageCollection) { if (this.AnalysisCollection.ContainsKey(item.Key) == false) { StandardDataAnalysis analysis = new StandardDataAnalysis(item.Key); analysis.UseTrimmed = this.chkTrimmed.Checked; analysis.TrimmedBegin = (double)this.numTrimmedBegin.Value; analysis.TrimmedEnd = (double)this.numTrimmedEnd.Value; this.AnalysisCollection.Add(item.Key, analysis); } this.AnalysisCollection[item.Key].AddRange(item.Value.ToArray()); } this.gridAnalysis.AutoBinding(this.AnalysisCollection.Values.ToArray()); } private void Grid_Setting() { this.grid.MultiSelect = true; this.grid.Columns.Clear(); this.grid.TableElement.RowHeight = 20; this.grid.AddColumn("MessageName"); this.grid.AddColumn("RequestTime"); this.grid.AddColumn("ResponseTime"); this.grid.AddColumn("Interval", "", true, "{0:#,##0.000}"); } private void GridAnalysis_Setting() { this.gridAnalysis.MultiSelect = true; this.gridAnalysis.Columns.Clear(); this.gridAnalysis.TableElement.RowHeight = 20; this.gridAnalysis.AddColumn("MessageName"); this.gridAnalysis.AddColumn("Count"); this.gridAnalysis.AddColumn("Min", "", true, "{0:#,##0.000}"); this.gridAnalysis.AddColumn("Max", "", true, "{0:#,##0.000}"); this.gridAnalysis.AddColumn("TrimmedMean", "절사평균", true, "{0:#,##0.000}"); this.gridAnalysis.AddColumn("TrimmedStdDeviation", "절사편차", true, "{0:#,##0.000}"); this.gridAnalysis.AddColumn("ArithmeticMean", "산술평균", true, "{0:#,##0.000}"); this.gridAnalysis.AddColumn("ArithmeticStdDeviation", "산술편차", true, "{0:#,##0.000}"); } private void Chart_Setting() { this.chart.ShowGrid = true; this.chart.ShowLegend = true; #if DateTimeAxis this.HorizontalAxis = new DateTimeContinuousAxis() { MajorStepUnit = TimeInterval.Hour, LabelFormatProvider = new DateTimeFormatProvider() }; this.VerticalAxis = new LinearAxis() { }; #else this.HorizontalAxis = new CategoricalAxis() { }; this.VerticalAxis = new LinearAxis() { }; #endif } private ChartSeries Chart_AddSeries(string name, StandardDataPair[] values) { LineSeries series = new LineSeries(); series.Name = name; //series.HorizontalAxis = this.HorizontalAxis; //series.VerticalAxis = this.VerticalAxis; series.PointSize = new SizeF(3, 3); series.BorderWidth = 2; series.CategoryMember = "RequestTime"; series.ValueMember = "Interval"; series.ShowLabels = this.chkShowLabel.Checked; series.Spline = true; series.CombineMode = ChartSeriesCombineMode.Stack; series.DataSource = values; this.chart.Series.Add(series); return series; } #endregion } public class DateTimeFormatProvider : IFormatProvider, ICustomFormatter { public object GetFormat(Type formatType) { return this; } public string Format(string format, object arg, IFormatProvider formatProvider) { DateTime val = (DateTime)arg; return val.ToString("HH:mm:ss"); } } public class StandardDataAnalysis : DataTableBase { /// MessageName public string MessageName { get; set; } = string.Empty; public int Count { get { return this.Collection.Count; } } public bool UseTrimmed { get; set; } = false; public double Min { get; set; } = -1; public double Max { get; set; } = -1; /// 산술평균 public double ArithmeticMean { get; set; } = 0; /// 산술평균>표준편차 public double ArithmeticStdDeviation { get; set; } = 0; /// 절사평균 public double TrimmedMean { get; set; } = 0; /// 절사평균>표준편차 public double TrimmedStdDeviation { get; set; } = 0; /// 절사평균 범위 public double TrimmedBegin { get; set; } = 0; /// 절사평균 범위 public double TrimmedEnd { get; set; } = 80; private List Collection { get; set; } = new List(); public StandardDataAnalysis() { } public StandardDataAnalysis(string name, params StandardDataPair[] value) { this.MessageName = name; this.Collection.AddRange(value); if (value.Length > 0) this.Calculation(); } public void AddRange(params StandardDataPair[] values) { this.Collection.AddRange(values); this.Calculation(); } private void Calculation() { double sum = 0; double average = 0; #region 절사평균 sum = 0; int trimStartIndex = (int)(this.Collection.Count * (this.TrimmedBegin / 100)); int trimEndIndex = (int)(this.Collection.Count * (this.TrimmedEnd / 100)); int trimCount = 0; int trimIndex = -1; foreach (StandardDataPair item in this.Collection.OrderBy(item => item.Interval)) { trimIndex++; if (trimIndex < trimStartIndex) continue; if (trimIndex > trimEndIndex) break; sum += item.Interval; trimCount++; } average = sum / trimCount; this.TrimmedMean = average; #endregion #region 산술평균 sum = 0; double min = -1; double max = -1; foreach (StandardDataPair item in this.Collection) { sum += item.Interval; if (item.Interval < min || min == -1) min = item.Interval; if (item.Interval > max || max == -1) max = item.Interval; } average = sum / this.Collection.Count; this.Min = min; this.Max = max; this.ArithmeticMean = average; #endregion double deviation = 0; double sumTrimVariance = 0; double sumArithmeticVariance = 0; double variance = 0; foreach (StandardDataPair item in this.Collection) { deviation = item.Interval - this.TrimmedMean; // 절사평균 편차 sumTrimVariance += Math.Pow(deviation, 2); deviation = item.Interval - this.ArithmeticMean; // 산술평균 편차 sumArithmeticVariance += Math.Pow(deviation, 2); } variance = sumTrimVariance / this.Collection.Count; // 절사평균 분산 this.TrimmedStdDeviation = Math.Sqrt(variance); // 절사평균 표준편차 variance = sumArithmeticVariance / this.Collection.Count; // 산술평균 분산 this.ArithmeticStdDeviation = Math.Sqrt(variance); // 산술평균 표준편차 } public bool CheckOver(StandardDataPair pair) { double average = 0; if (this.UseTrimmed) average = this.ArithmeticMean; else average = this.TrimmedMean; double min = average - (this.ArithmeticStdDeviation / 2); double max = average + (this.ArithmeticStdDeviation / 2); if (pair.Interval > max) return true; return false; } } }