580 lines
20 KiB
C#
580 lines
20 KiB
C#
#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<string, StandardDataAnalysis> AnalysisCollection = new Dictionary<string, StandardDataAnalysis>();
|
|
|
|
private CartesianAxis HorizontalAxis { get; set; } = null;
|
|
|
|
private LinearAxis VerticalAxis { get; set; } = null;
|
|
|
|
#endregion
|
|
|
|
#region [ Properties ] ================================================
|
|
|
|
public StandardCollection StandardCollection { get; set; } = null;
|
|
|
|
public Dictionary<string, List<StandardDataPair>> MessageCollection { get; set; } = new Dictionary<string, List<StandardDataPair>>();
|
|
|
|
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<StandardDataPair> lst = new List<StandardDataPair>();
|
|
if (string.IsNullOrEmpty(this.cboxMessageName.Text))
|
|
{
|
|
foreach (KeyValuePair<string, List<StandardDataPair>> 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<string> lstMessage = new List<string>();
|
|
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<string, List<StandardDataPair>> dicSrc = new Dictionary<string, List<StandardDataPair>>();
|
|
|
|
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>());
|
|
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<string, List<StandardDataPair>> 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<StandardDataPair>());
|
|
this.MessageCollection[key].Add(pair);
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
XLogger.Instance.Fatal(ex);
|
|
}
|
|
}
|
|
|
|
private void DataAnalysis()
|
|
{
|
|
this.AnalysisCollection.Clear();
|
|
|
|
foreach (KeyValuePair<string, List<StandardDataPair>> 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
|
|
{
|
|
|
|
/// <summary>MessageName</summary>
|
|
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;
|
|
|
|
/// <summary>산술평균</summary>
|
|
public double ArithmeticMean { get; set; } = 0;
|
|
|
|
/// <summary>산술평균>표준편차</summary>
|
|
public double ArithmeticStdDeviation { get; set; } = 0;
|
|
|
|
/// <summary>절사평균</summary>
|
|
public double TrimmedMean { get; set; } = 0;
|
|
|
|
/// <summary>절사평균>표준편차</summary>
|
|
public double TrimmedStdDeviation { get; set; } = 0;
|
|
|
|
/// <summary>절사평균 범위</summary>
|
|
public double TrimmedBegin { get; set; } = 0;
|
|
|
|
/// <summary>절사평균 범위</summary>
|
|
public double TrimmedEnd { get; set; } = 80;
|
|
|
|
private List<StandardDataPair> Collection { get; set; } = new List<StandardDataPair>();
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
}
|