diff --git a/.gitignore b/.gitignore
index a9dfc27..0cee943 100644
--- a/.gitignore
+++ b/.gitignore
@@ -362,5 +362,5 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
-Data
+TrainData
prometheus-2.45.0-rc.0.windows-amd64
\ No newline at end of file
diff --git a/DeepTrace/Controls/TimeSeriesChart.razor b/DeepTrace/Controls/TimeSeriesChart.razor
index 713f12e..8e7e6a5 100644
--- a/DeepTrace/Controls/TimeSeriesChart.razor
+++ b/DeepTrace/Controls/TimeSeriesChart.razor
@@ -1,33 +1,42 @@
@using PrometheusAPI;
-
+
+ @foreach (var ts in _currentData.Series)
+ {
+
+ }
+
@code {
+ public class TimeSeriesDataSet
+ {
+ public string Name { get; init; } = "Value";
+ public string Color { get; init; } = "";
+ public IReadOnlyCollection Data { get; init; } = Array.Empty();
+ }
+
+ public class TimeSeriesData
+ {
+ public List Series { get; init; } = new List();
+ }
+
+
[CascadingParameter]
protected bool IsDarkMode { get; set; }
- [Parameter] public IList? Data { get; set; }
+ [Parameter] public TimeSeriesData? Data { get; set; }
[Parameter] public DateTime? MinDate { get; set; }
[Parameter] public DateTime? MaxDate { get; set; }
@@ -36,10 +45,7 @@
private ApexChart? _chart;
private ApexChartOptions? _options;
- private IList? _currentData;
-
- private bool IsChartHidden => _currentData == null;
- private bool IsChartShown => !IsChartHidden;
+ private TimeSeriesData _currentData = new() { Series = { new () } };
protected override void OnInitialized()
{
@@ -60,9 +66,10 @@
if (Data == _currentData)
return;
- _currentData = Data;
+ _currentData = Data ?? new() { Series = { new() } }; ;
+ _options = CreateOptions();
- if (_currentData == null)
+ if (_chart == null)
return;
//await InvokeAsync(StateHasChanged);
@@ -77,10 +84,7 @@
var backgroundColor = IsDarkMode ? "var(--mud-palette-surface)" : "#f3f3f3";
var gridColor = IsDarkMode ? "var(--mud-palette-drawer-background)" : "#f3f3f3";
var borderColor = IsDarkMode ? "var(--mud-palette-text-primary)" : "#e7e7e7";
- var lineColors = IsDarkMode
- ? new List { "#F57F17", "#00838F" }
- : new List { "#77B6EA", "#545454" }
- ;
+ var lineColors = _currentData.Series.Select( x => x.Color).ToList();
var mode = IsDarkMode
? Mode.Dark
: Mode.Light
@@ -139,7 +143,7 @@
}
},
Colors = lineColors,
- Markers = new() { Shape = ShapeEnum.Circle, Size = 2, FillOpacity = new Opacity(0.8d) },
+ //Markers = new() { Shape = ShapeEnum.Circle, Size = 2, FillOpacity = new Opacity(0.8d) },
Stroke = new() { Curve = Curve.Straight, Width = 2 },
Legend = new()
{
@@ -168,12 +172,12 @@
DateTimeOffset xMax;
xMin = zoomedData.XAxis?.Min == null
- ? Data!.Min(e => e.TimeStamp.Date)
+ ? _currentData!.Series.First().Data.Min(e => e.TimeStamp.Date)
: DateTimeOffset.FromUnixTimeMilliseconds((long)zoomedData.XAxis.Min)
;
xMax = zoomedData.XAxis?.Max == null
- ? Data!.Max(e => e.TimeStamp.Date)
+ ? _currentData!.Series.First().Data.Max(e => e.TimeStamp.Date)
: DateTimeOffset.FromUnixTimeMilliseconds((long)zoomedData.XAxis.Max)
;
diff --git a/DeepTrace/Data/DataSourceDefinition.cs b/DeepTrace/Data/DataSourceDefinition.cs
new file mode 100644
index 0000000..0002a21
--- /dev/null
+++ b/DeepTrace/Data/DataSourceDefinition.cs
@@ -0,0 +1,29 @@
+namespace DeepTrace.Data;
+
+public class DataSourceQuery
+{
+
+ public DataSourceQuery(string query, string color)
+ {
+ Query = query;
+ Color = color;
+ }
+
+ public string Query { get; set; }
+ public MudBlazor.Utilities.MudColor Color { get; set; }
+
+}
+
+public class DataSourceDefinition
+{
+ private static int _instanceId;
+ public DataSourceDefinition()
+ {
+ var id = Interlocked.Increment(ref _instanceId);
+ Name = $"Dataset #{id}";
+ }
+
+ public string Name { get; set; }
+ public List Queries { get; set; } = new();
+ public string Description { get; set; } = string.Empty;
+}
diff --git a/DeepTrace/Data/DataViewHelper.cs b/DeepTrace/Data/DataViewHelper.cs
new file mode 100644
index 0000000..98b0609
--- /dev/null
+++ b/DeepTrace/Data/DataViewHelper.cs
@@ -0,0 +1,52 @@
+using Microsoft.ML;
+using PrometheusAPI;
+using System.Data;
+
+namespace DeepTrace.Data;
+public static class DataViewHelper
+{
+ public static DataTable? ToDataTable(this IDataView dataView)
+ {
+ DataTable? dt = null;
+ if (dataView != null)
+ {
+ dt = new DataTable();
+ var preview = dataView.Preview();
+ dt.Columns.AddRange(preview.Schema.Select(x => new DataColumn(x.Name)).ToArray());
+ foreach (var row in preview.RowView)
+ {
+ var r = dt.NewRow();
+ foreach (var col in row.Values)
+ {
+ r[col.Key] = col.Value;
+ }
+ dt.Rows.Add(r);
+
+ }
+ }
+ return dt;
+ }
+
+ public static List ToTimeSeries(this IDataView dataView)
+ {
+ var dt = new List();
+ if (dataView == null)
+ {
+ return dt;
+ }
+
+ var preview = dataView.Preview();
+ var tsCol = preview.Schema["TimeStamp"];
+ var valCol = preview.Schema["Value"];
+
+ foreach (var row in preview.RowView)
+ {
+ var r = new TimeSeries(
+ Convert.ToDateTime(row.Values[tsCol.Index].Value),
+ (float)Convert.ToDouble(row.Values[valCol.Index].Value)
+ );
+ dt.Add(r);
+ }
+ return dt;
+ }
+}
diff --git a/DeepTrace/Data/MLModel1.mbconfig b/DeepTrace/Data/MLModel1.mbconfig
new file mode 100644
index 0000000..94ebac1
--- /dev/null
+++ b/DeepTrace/Data/MLModel1.mbconfig
@@ -0,0 +1,6 @@
+{
+ "TrainingTime": 0,
+ "Scenario": "Default",
+ "Type": "TrainingConfig",
+ "Version": 2
+}
\ No newline at end of file
diff --git a/DeepTrace/Data/Prediction.cs b/DeepTrace/Data/Prediction.cs
new file mode 100644
index 0000000..97d8502
--- /dev/null
+++ b/DeepTrace/Data/Prediction.cs
@@ -0,0 +1,15 @@
+using Microsoft.ML.Data;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DeepTrace.Data;
+
+public class MyPrediction
+{
+ //vector to hold alert,score,p-value values
+ [VectorType(3)]
+ public double[]? Prediction { get; set; }
+}
diff --git a/DeepTrace/Pages/FetchData.razor b/DeepTrace/Pages/FetchData.razor
index 77936fe..1d73a57 100644
--- a/DeepTrace/Pages/FetchData.razor
+++ b/DeepTrace/Pages/FetchData.razor
@@ -25,12 +25,53 @@
+
+
+
+
+ @foreach (var source in _dataSources)
+ {
+ @source.Name
+ }
+
+ Add
+ @if (_dataSources.Count > 1)
+ {
+ Delete
+ }
+
+
+
-
+
+
+
+
+ @for ( var i = 0; i < _queryForm.Source.Queries.Count; i++ )
+ {
+ int pos = i;
+ var def = _queryForm.Source.Queries[pos];
+
+
+
+
+
+
+ @if (_queryForm.Source.Queries.Count > 1)
+ {
+
+ }
+
+
+
+
+ }
+
+
Clear
@@ -38,9 +79,11 @@
Ok
+
@**@
+
Submit
@@ -51,7 +94,10 @@
-
+
+
+
+
@@ -66,7 +112,7 @@
private class PrometheusForm
{
[Required]
- public string? Query { get; set; } = """ec2_cpu_utilization_24ae8d""";
+ public DataSourceDefinition Source { get; set; } = new();
public DateRange Dates { get; set; } = new DateRange(DateTime.UtcNow.Date - TimeSpan.FromDays(14), DateTime.UtcNow.Date);
@@ -82,8 +128,21 @@
}
private PrometheusForm _queryForm = new();
+ private List _dataSources = new()
+ {
+ new()
+ {
+ Queries =
+ {
+ new("""ec2_cpu_utilization_24ae8d""", "#F57F17")
+ }
+ }
+ };
private MudDateRangePicker? _picker;
+ private bool IsChartHidden => DisplayData == null;
+ private bool IsChartShown => !IsChartHidden;
+
private DateTime? MinDate
{
get => _queryForm.Dates.Start?.Date + _queryForm.TimeStart;
@@ -120,11 +179,72 @@
}
}
- private List? DisplayData { get; set; }
+ private TimeSeriesChart.TimeSeriesData? DisplayData { get; set; }
+
+ private string[] _palette = new[]
+ {
+ "#F44336", "#E91E63", "#9C27B0", "#673AB7", "#3F51B5",
+ "#FFEBEE", "#FCE4EC", "#F3E5F5", "#EDE7F6", "#E8EAF6",
+ "#FFCDD2", "#F8BBD0", "#E1BEE7", "#D1C4E9", "#C5CAE9",
+ "#EF9A9A", "#F48FB1", "#CE93D8", "#B39DDB", "#9FA8DA",
+ "#E57373", "#F06292", "#BA68C8", "#9575CD", "#7986CB",
+ "#EF5350", "#EC407A", "#AB47BC", "#7E57C2", "#5C6BC0",
+ "#E53935", "#D81B60", "#8E24AA", "#5E35B1", "#3949AB"
+ };
+
+
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+ _queryForm.Source = _dataSources[0];
+ }
+
+ private void AddQuery(int pos)
+ {
+ pos += 1;
+ var color = pos < _palette.Length
+ ? _palette[pos]
+ : "#F44336"
+ ;
+ _queryForm.Source.Queries.Insert(pos, new("",color));
+ StateHasChanged();
+ }
+
+ private void DeleteQuery(int pos)
+ {
+ _queryForm.Source.Queries.RemoveAt(pos);
+ StateHasChanged();
+ }
+
+
+ private void HandleAddSource()
+ {
+ _dataSources.Add(new() { Queries = { new("", _palette[0]) } });
+ _queryForm.Source = _dataSources[^1];
+ StateHasChanged();
+ }
+
+ private void HandleDeleteSource()
+ {
+ if (_dataSources.Count < 2)
+ {
+ return;
+ }
+
+ var pos = _dataSources.IndexOf(_queryForm.Source);
+ if (pos < 0)
+ {
+ ShowError("Not found");
+ return;
+ }
+ _dataSources.RemoveAt(pos);
+ _queryForm.Source = _dataSources[pos<_dataSources.Count ? pos: _dataSources.Count-1];
+ StateHasChanged();
+ }
private async Task HandleSubmit()
{
- if (string.IsNullOrWhiteSpace(_queryForm.Query) || _queryForm.Dates.End == null || _queryForm.Dates.Start == null)
+ if (_queryForm.Source.Queries.Count < 1 || string.IsNullOrWhiteSpace(_queryForm.Source.Queries[0].Query) || _queryForm.Dates.End == null || _queryForm.Dates.Start == null)
return;
var startTime = _queryForm.TimeStart
@@ -146,16 +266,8 @@
var startDate = _queryForm.Dates.Start.Value.Date + startTime;
var endDate = _queryForm.Dates.End.Value.Date + endTime;
- try
- {
- var formatted = await Prometheus.FormatQuery(_queryForm.Query);
- _queryForm.Query = formatted;
- }
- catch (Exception e)
- {
- ShowError(e.Message);
+ if (!await FormatQueries())
return;
- }
TimeSpan step;
@@ -167,36 +279,90 @@
seconds = 1.0;
step = TimeSpan.FromSeconds(seconds);
- var res = await Prometheus.RangeQuery(_queryForm.Query, startDate, endDate, step, TimeSpan.FromSeconds(2));
+ var tasks = _queryForm.Source.Queries
+ .Select(x => Prometheus.RangeQuery(x.Query, startDate, endDate, step, TimeSpan.FromSeconds(2)))
+ .ToArray();
- if (res.Status != StatusType.Success)
+ try
{
- ShowError(res.Error ?? "Error");
+ await Task.WhenAll(tasks);
+ }
+ catch ( Exception e )
+ {
+ ShowError(e.Message);
return;
}
- if (res.ResultType != ResultTypeType.Matrix)
+ var data = new List();
+
+ foreach ( var (res, def) in tasks.Select((x,i) => (x.Result, _queryForm.Source.Queries[i]) ))
{
- ShowError($"Got {res.ResultType}, but Matrix expected");
- return;
+ if (res.Status != StatusType.Success)
+ {
+ ShowError(res.Error ?? "Error");
+ return;
+ }
+
+ if (res.ResultType != ResultTypeType.Matrix)
+ {
+ ShowError($"Got {res.ResultType}, but Matrix expected for {def.Query}");
+ return;
+ }
+
+ var m = res.AsMatrix().Result;
+ if (m == null || m.Length != 1)
+ {
+ ShowError($"No data returned for {def.Query}");
+ return;
+ }
+
+ data.Add(
+ new()
+ {
+ Name = def.Query,
+ Color = def.Color.Value,
+ Data = m[0].Values!.ToList()
+ }
+ );
}
- var m = res.AsMatrix().Result;
- if (m == null || m.Length != 1)
- {
- ShowError("No data returned");
- return;
- }
+ DisplayData = new() { Series = data };
+ await InvokeAsync(StateHasChanged);
+
+ // --------------------- playground -----------------------------
var mlContext = new MLContext();
- DisplayData = m[0].Values!.ToList();
- var dataView = mlContext.Data.LoadFromEnumerable(DisplayData.Select(x => new MyTimeSeries(Time: x.TimeStamp, Value: x.Value)));
+
+ var dataView = mlContext.Data.LoadFromEnumerable(DisplayData.Series[0].Data.Select(x => new MyTimeSeries(Time: x.TimeStamp, Value: x.Value)));
//DetectSpike(mlContext, dataView, data);
int period = DetectPeriod(mlContext, dataView);
DetectAnomaly(mlContext, dataView, period);
- await InvokeAsync(StateHasChanged);
+ }
+
+ private async Task FormatQueries()
+ {
+ try
+ {
+ var formatTasks = _queryForm.Source.Queries
+ .Select(x => Prometheus.FormatQuery(x.Query))
+ .ToArray();
+
+ await Task.WhenAll(formatTasks);
+
+ for ( var i = 0; i < formatTasks.Length; i++ )
+ {
+ _queryForm.Source.Queries[i].Query = formatTasks[i].Result;
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ ShowError(e.Message);
+ return false;
+ }
}
private record MyTimeSeries(DateTime Time, double Value);