Skip to content

Commit 182b429

Browse files
committed
refactored how context collections are stored and improved search capabilities.
1 parent 2a61d3e commit 182b429

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+851
-104
lines changed

src/Server/Coderr.Server.Api/Core/Incidents/Queries/FindIncidents.cs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,49 @@ public FindIncidents()
2323
ItemsPerPage = 20;
2424
}
2525

26+
2627
/// <summary>
27-
/// 0 = find for all applications
28+
/// Find incidents assigned to the specified user
29+
/// </summary>
30+
public int AccountId { get; set; }
31+
32+
/// <summary>
33+
/// Empty = find for all applications
2834
/// </summary>
2935
/// <value>
3036
/// The application identifier.
3137
/// </value>
32-
public int ApplicationId { get; set; }
38+
public int[] ApplicationIds { get; set; }
39+
40+
/// <summary>
41+
/// Find an incident with a specific collection
42+
/// </summary>
43+
/// <remarks>
44+
/// <para>
45+
/// Wildcard search is allowed, i.e. "http*"
46+
/// </para>
47+
/// </remarks>
48+
public string ContextCollectionName { get; set; }
49+
50+
/// <summary>
51+
/// Find an incident with a specific property
52+
/// </summary>
53+
/// <remarks>
54+
/// <para>
55+
/// Wildcard search is allowed, i.e. "http*"
56+
/// </para>
57+
/// </remarks>
58+
public string ContextCollectionPropertyName { get; set; }
59+
60+
/// <summary>
61+
/// Find an incident with a specific property value
62+
/// </summary>
63+
/// <remarks>
64+
/// <para>
65+
/// Wildcard search is allowed, i.e. "http*"
66+
/// </para>
67+
/// </remarks>
68+
public string ContextCollectionPropertyValue { get; set; }
3369

3470
/// <summary>
3571
/// Will be searched in incident.message and report.stacktrace.
@@ -91,11 +127,14 @@ public FindIncidents()
91127
/// </summary>
92128
public IncidentOrder SortType { get; set; }
93129

130+
/// <summary>
131+
/// Incident should have all the specified tags
132+
/// </summary>
133+
public string[] Tags { get; set; }
134+
94135
/// <summary>
95136
/// Version (in the form of a version string i.e. "1.2.1")
96137
/// </summary>
97138
public string Version { get; set; }
98-
99-
public string[] Tags { get; set; }
100139
}
101140
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using DotNetCqs;
2+
3+
namespace codeRR.Server.Api.Modules.Tagging.Queries
4+
{
5+
/// <summary>
6+
/// Get all tags that the system have identified for an incident.
7+
/// </summary>
8+
[Message]
9+
public class GetTags : Query<TagDTO[]>
10+
{
11+
/// <summary>
12+
/// Application to get tags for
13+
/// </summary>
14+
public int? ApplicationId { get; set; }
15+
16+
/// <summary>
17+
/// Incident to get tags for
18+
/// </summary>
19+
public int? IncidentId { get; private set; }
20+
}
21+
}

src/Server/Coderr.Server.App/Core/Reports/Jobs/DeleteReportsBelowReportLimit.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public void Execute()
5959
{
6060
cmd.CommandText =
6161
@"SELECT TOP(5) IncidentId, count(Id)
62-
FROM ErrorReports
62+
FROM ErrorReports WITH (ReadPast)
6363
GROUP BY IncidentId
6464
HAVING Count(IncidentId) > @max
6565
ORDER BY count(Id) DESC";
@@ -82,9 +82,8 @@ HAVING Count(IncidentId) > @max
8282
var sql = $@"With RowsToDelete AS
8383
(
8484
SELECT TOP {rowsToDelete} Id
85-
FROM ErrorReports
85+
FROM ErrorReports WITH (ReadPast)
8686
WHERE IncidentId = {incidentIdAndCount.Item1}
87-
ORDER BY ID ASC
8887
)
8988
DELETE FROM RowsToDelete";
9089
cmd.CommandText = sql;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Linq;
2+
using System.Threading.Tasks;
3+
using codeRR.Server.Api.Modules.Tagging;
4+
using codeRR.Server.Api.Modules.Tagging.Queries;
5+
using codeRR.Server.App.Modules.Tagging.Domain;
6+
using DotNetCqs;
7+
using Griffin.Container;
8+
9+
namespace codeRR.Server.App.Modules.Tagging.Handlers
10+
{
11+
[Component]
12+
internal class GetTagsHandler : IQueryHandler<GetTags, TagDTO[]>
13+
{
14+
private readonly ITagsRepository _repository;
15+
16+
public GetTagsHandler(ITagsRepository repository)
17+
{
18+
_repository = repository;
19+
}
20+
21+
public async Task<TagDTO[]> HandleAsync(IMessageContext context, GetTags query)
22+
{
23+
return (await _repository.GetTagsAsync(query.ApplicationId, query.IncidentId)).Select(ConvertTag).ToArray();
24+
}
25+
26+
private TagDTO ConvertTag(Tag arg)
27+
{
28+
return new TagDTO {Name = arg.Name, OrderNumber = arg.OrderNumber};
29+
}
30+
}
31+
}

src/Server/Coderr.Server.App/Modules/Tagging/ITagsRepository.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ public interface ITagsRepository
1818
/// <returns>task</returns>
1919
Task AddAsync(int incidentId, Tag[] tags);
2020

21+
/// <summary>
22+
/// Get a list of tags for an application
23+
/// </summary>
24+
/// <param name="applicationId">application to get tags for</param>
25+
/// <returns>List of tags (or an empty list)</returns>
26+
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
27+
Task<IReadOnlyList<Tag>> GetApplicationTagsAsync(int applicationId);
28+
2129
/// <summary>
2230
/// Get a list of tags for a specific incident
2331
/// </summary>
@@ -30,8 +38,9 @@ public interface ITagsRepository
3038
/// Get a list of tags for an application
3139
/// </summary>
3240
/// <param name="applicationId">application to get tags for</param>
41+
/// <param name="incidentId">incident to get tags for</param>
3342
/// <returns>List of tags (or an empty list)</returns>
3443
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
35-
Task<IReadOnlyList<Tag>> GetApplicationTagsAsync(int applicationId);
44+
Task<IReadOnlyList<Tag>> GetTagsAsync(int? applicationId, int? incidentId);
3645
}
3746
}

src/Server/Coderr.Server.ReportAnalyzer/AnalysisDbContext.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Data;
33
using codeRR.Server.Infrastructure;
4+
using codeRR.Server.ReportAnalyzer.Domain.Reports;
45
using Griffin.Data;
56

67
namespace codeRR.Server.ReportAnalyzer
@@ -12,17 +13,15 @@ public class AnalysisDbContext : IDisposable
1213
{
1314
private readonly Func<IDbConnection> _connectionFactory;
1415
private IDbConnection _con;
15-
private IAdoNetUnitOfWork _unitOfWork;
16+
private OurUnitOfWork _unitOfWork;
1617

1718
public AnalysisDbContext(Func<IDbConnection> connectionFactory)
1819
{
1920
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
2021
}
2122

22-
public AnalysisDbContext(IAdoNetUnitOfWork unitOfWork)
23-
{
24-
_unitOfWork = unitOfWork ?? throw new ArgumentNullException(nameof(unitOfWork));
25-
}
23+
24+
public IDbTransaction Transaction => ((OurUnitOfWork) UnitOfWork).Transaction;
2625

2726
/// <summary>
2827
/// Open and valid connection
@@ -45,12 +44,17 @@ public IDbConnection Connection
4544
/// </summary>
4645
/// <exception cref="DataException">Connection failed.</exception>
4746
public IAdoNetUnitOfWork UnitOfWork => _unitOfWork
48-
?? (_unitOfWork = new AdoNetUnitOfWork(Connection, false));
47+
?? (_unitOfWork = new OurUnitOfWork(Connection, false));
4948

5049
public void Dispose()
5150
{
5251
_unitOfWork?.Dispose();
5352
_con?.Dispose();
5453
}
54+
55+
public void SaveChanges()
56+
{
57+
_unitOfWork?.SaveChanges();
58+
}
5559
}
5660
}

src/Server/Coderr.Server.ReportAnalyzer/IAnalyticsRepository.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@ public interface IAnalyticsRepository
5656
/// <param name="incidentAnalysis">incident to persist</param>
5757
/// <exception cref="ArgumentNullException">incentAnalysis</exception>
5858
void UpdateIncident(IncidentBeingAnalyzed incidentAnalysis);
59+
5960
}
6061
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using System;
2+
using System.Data;
3+
using Griffin;
4+
using Griffin.Data;
5+
6+
namespace codeRR.Server.ReportAnalyzer
7+
{
8+
public class OurUnitOfWork : IAdoNetUnitOfWork
9+
{
10+
private readonly bool _ownsConnection;
11+
private IDbConnection _connection;
12+
13+
public OurUnitOfWork(IDbConnection connection, bool ownsConnection)
14+
{
15+
_connection = connection ?? throw new ArgumentNullException(nameof(connection));
16+
_ownsConnection = ownsConnection;
17+
Transaction = connection.BeginTransaction();
18+
}
19+
20+
public IDbTransaction Transaction { get; private set; }
21+
22+
public void Dispose()
23+
{
24+
if (Transaction != null)
25+
{
26+
Transaction.Dispose();
27+
Transaction = null;
28+
}
29+
30+
if (_connection != null && _ownsConnection)
31+
{
32+
_connection.Dispose();
33+
_connection = null;
34+
}
35+
}
36+
37+
public void SaveChanges()
38+
{
39+
Transaction.Commit();
40+
Transaction.Dispose();
41+
Transaction = null;
42+
}
43+
44+
public IDbCommand CreateCommand()
45+
{
46+
var cmd = _connection.CreateCommand();
47+
cmd.Transaction = Transaction;
48+
return cmd;
49+
}
50+
51+
/// <summary>
52+
/// Execute a SQL query within the transaction
53+
/// </summary>
54+
/// <param name="sql"></param>
55+
/// <param name="parameters"></param>
56+
public void Execute(string sql, object parameters)
57+
{
58+
using (var cmd = CreateCommand())
59+
{
60+
cmd.CommandText = sql;
61+
var dictionary = parameters.ToDictionary();
62+
foreach (var kvp in dictionary) cmd.AddParameter(kvp.Key, kvp.Value);
63+
cmd.ExecuteNonQuery();
64+
}
65+
}
66+
}
67+
}

src/Server/Coderr.Server.SqlServer/Analysis/AnalyticsRepository.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using codeRR.Server.ReportAnalyzer.Domain.Incidents;
1010
using codeRR.Server.ReportAnalyzer.Domain.Reports;
1111
using codeRR.Server.ReportAnalyzer.Scanners;
12+
using codeRR.Server.SqlServer.Analysis.Jobs;
1213
using codeRR.Server.SqlServer.Tools;
1314
using Coderr.Server.PluginApi.Config;
1415
using DotNetCqs;
@@ -26,6 +27,7 @@ public class AnalyticsRepository : IAnalyticsRepository
2627
private readonly ILog _logger = LogManager.GetLogger(typeof(AnalyticsRepository));
2728
private readonly ReportDtoConverter _reportDtoConverter = new ReportDtoConverter();
2829
private readonly IAdoNetUnitOfWork _unitOfWork;
30+
private const int MaxCollectionSize = 2000000;
2931

3032
public AnalyticsRepository(AnalysisDbContext dbContext, ConfigurationStore configurationStore)
3133
{
@@ -111,8 +113,35 @@ public void CreateReport(ErrorReportEntity report)
111113
report.Title = report.Title.Substring(0, 100);
112114
}
113115

116+
var collections = new List<string>();
117+
foreach (var context in report.ContextInfo)
118+
{
119+
var data = EntitySerializer.Serialize(context);
120+
if (data.Length > MaxCollectionSize)
121+
{
122+
var tooLargeCtx = new ErrorReportContext(context.Name,
123+
new Dictionary<string, string>()
124+
{
125+
{
126+
"Error",
127+
$"This collection was larger ({data.Length}bytes) than the threshold of {MaxCollectionSize}bytes"
128+
}
129+
});
130+
131+
data = EntitySerializer.Serialize(tooLargeCtx);
132+
}
133+
collections.Add(data);
134+
}
135+
136+
var cols = string.Join(", ", collections);
137+
var inboound = new InboundCollection
138+
{
139+
JsonData = $"[{cols}]",
140+
ReportId = report.Id
141+
};
114142

115143
_unitOfWork.Insert(report);
144+
_unitOfWork.Insert(inboound);
116145
}
117146

118147
public string GetAppName(int applicationId)

src/Server/Coderr.Server.SqlServer/Analysis/ErrorReportEntityMapper.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ public ErrorReportEntityMapper() : base("ErrorReports")
1616
.ToColumnValue(EntitySerializer.Serialize);
1717

1818
Property(x => x.ContextInfo)
19-
.ToPropertyValue(EntitySerializer.Deserialize<ErrorReportContext[]>)
20-
.ToColumnValue(EntitySerializer.Serialize);
19+
.Ignore();
2120

2221
Property(x => x.ClientReportId)
2322
.ColumnName("ErrorId");

0 commit comments

Comments
 (0)