Skip to content

Commit 1f92732

Browse files
committed
improve query logging
1 parent 7f3e02f commit 1f92732

File tree

6 files changed

+195
-124
lines changed

6 files changed

+195
-124
lines changed

src/FluentCommand.Generators/Properties/launchSettings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
"FluentCommand.Tests": {
44
"commandName": "DebugRoslynComponent",
55
"targetProject": "..\\..\\test\\FluentCommand.Tests\\FluentCommand.Tests.csproj"
6+
},
7+
"FluentCommand.Entities": {
8+
"commandName": "DebugRoslynComponent",
9+
"targetProject": "..\\..\\test\\FluentCommand.Entities\\FluentCommand.Entities.csproj"
610
}
711
}
812
}
Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
using System.Data;
2+
using System.Text;
3+
4+
using FluentCommand.Extensions;
5+
using FluentCommand.Internal;
26

37
using Microsoft.Extensions.Logging;
48

59
namespace FluentCommand;
610

711
/// <summary>
8-
/// A class for logging queries
12+
/// A class for logging queries
913
/// </summary>
1014
/// <seealso cref="FluentCommand.IDataQueryLogger" />
1115
public partial class DataQueryLogger : IDataQueryLogger
1216
{
13-
private readonly ILogger<DataQueryLogger> _logger;
14-
private readonly IDataQueryFormatter _formatter;
1517

1618
/// <summary>
1719
/// Initializes a new instance of the <see cref="DataQueryLogger"/> class.
1820
/// </summary>
1921
/// <param name="logger">The logger.</param>
20-
/// <param name="formatter">The formatter for the data command</param>
21-
public DataQueryLogger(ILogger<DataQueryLogger> logger, IDataQueryFormatter formatter)
22+
public DataQueryLogger(ILogger<DataQueryLogger> logger)
2223
{
23-
_logger = logger;
24-
_formatter = formatter;
24+
Logger = logger;
2525
}
2626

27+
protected ILogger Logger { get; }
28+
2729
/// <summary>
2830
/// Log the current specified <paramref name="command" />
2931
/// </summary>
@@ -34,23 +36,69 @@ public DataQueryLogger(ILogger<DataQueryLogger> logger, IDataQueryFormatter form
3436
/// <exception cref="System.ArgumentNullException">command</exception>
3537
public virtual void LogCommand(IDbCommand command, TimeSpan duration, Exception exception = null, object state = null)
3638
{
37-
if (_logger == null)
39+
if (Logger == null)
3840
return;
3941

4042
if (command is null)
4143
throw new ArgumentNullException(nameof(command));
4244

43-
var output = _formatter.FormatCommand(command, duration, exception);
45+
var elapsed = duration.TotalMilliseconds;
46+
var commandType = command.CommandType;
47+
var commandTimeout = command.CommandTimeout;
48+
var commandText = command.CommandText;
49+
var parameterText = FormatParameters(command);
4450

4551
if (exception == null)
46-
LogCommand(output);
52+
LogCommand(Logger, elapsed, commandType, commandTimeout, commandText, parameterText);
4753
else
48-
LogError(output, exception);
54+
LogError(Logger, elapsed, commandType, commandTimeout, commandText, parameterText, exception);
55+
}
56+
57+
protected static string FormatParameters(IDbCommand command)
58+
{
59+
if (command is null || command.Parameters == null || command.Parameters.Count == 0)
60+
return string.Empty;
61+
62+
var parameterText = StringBuilderCache.Acquire();
63+
64+
foreach (IDataParameter parameter in command.Parameters)
65+
{
66+
int precision = 0;
67+
int scale = 0;
68+
int size = 0;
69+
70+
if (parameter is IDbDataParameter dataParameter)
71+
{
72+
precision = dataParameter.Precision;
73+
scale = dataParameter.Scale;
74+
size = dataParameter.Size;
75+
}
76+
77+
parameterText
78+
.AppendLineIf(() => parameterText.Length > 0)
79+
.Append("-- ")
80+
.Append(parameter.ParameterName)
81+
.Append(": ")
82+
.Append(parameter.Direction)
83+
.Append(" ")
84+
.Append(parameter.DbType)
85+
.Append("(Size=")
86+
.Append(size)
87+
.Append("; Precision=")
88+
.Append(precision)
89+
.Append("; Scale=")
90+
.Append(scale)
91+
.Append(") [")
92+
.Append(parameter.Value)
93+
.Append("]");
94+
}
95+
96+
return parameterText.ToString();
4997
}
5098

51-
[LoggerMessage(0, LogLevel.Debug, "{output}")]
52-
private partial void LogCommand(string output);
99+
[LoggerMessage(0, LogLevel.Debug, "Executed DbCommand ({Elapsed} ms) [CommandType='{CommandType}', CommandTimeout='{CommandTimeout}']\r\n{CommandText}\r\n{ParameterText}")]
100+
protected static partial void LogCommand(ILogger logger, double elapsed, CommandType commandType, int commandTimeout, string commandText, string parameterText);
53101

54-
[LoggerMessage(1, LogLevel.Error, "{output}")]
55-
private partial void LogError(string output, Exception exception);
102+
[LoggerMessage(1, LogLevel.Error, "Error Executing DbCommand ({Elapsed} ms) [CommandType='{CommandType}', CommandTimeout='{CommandTimeout}']\r\n{CommandText}\r\n{ParameterText}")]
103+
protected static partial void LogError(ILogger logger, double elapsed, CommandType commandType, int commandTimeout, string commandText, string parameterText, Exception exception);
56104
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using System.Text;
2+
3+
namespace FluentCommand.Extensions;
4+
5+
/// <summary>
6+
/// <see cref="StringBuilder"/> extension methods
7+
/// </summary>
8+
public static class StringBuilderExtensions
9+
{
10+
/// <summary>
11+
/// Appends a copy of the specified string followed by the default line terminator to the end of the StringBuilder object.
12+
/// </summary>
13+
/// <param name="sb">The StringBuilder instance to append to.</param>
14+
/// <param name="format">A composite format string.</param>
15+
/// <param name="args">An object array that contains zero or more objects to format.</param>
16+
public static StringBuilder AppendLine(this StringBuilder sb, string format, params object[] args)
17+
{
18+
sb.AppendFormat(format, args);
19+
sb.AppendLine();
20+
return sb;
21+
}
22+
23+
/// <summary>
24+
/// Appends a copy of the specified string if <paramref name="condition"/> is met.
25+
/// </summary>
26+
/// <param name="sb">The StringBuilder instance to append to.</param>
27+
/// <param name="text">The string to append.</param>
28+
/// <param name="condition">The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.</param>
29+
public static StringBuilder AppendIf(this StringBuilder sb, string text, Func<string, bool> condition = null)
30+
{
31+
var c = condition ?? (s => !string.IsNullOrEmpty(s));
32+
33+
if (c(text))
34+
sb.Append(text);
35+
36+
return sb;
37+
}
38+
39+
/// <summary>
40+
/// Appends a copy of the specified string if <paramref name="condition"/> is met.
41+
/// </summary>
42+
/// <param name="sb">The StringBuilder instance to append to.</param>
43+
/// <param name="text">The string to append.</param>
44+
/// <param name="condition">The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.</param>
45+
public static StringBuilder AppendIf(this StringBuilder sb, string text, bool condition)
46+
{
47+
if (condition)
48+
sb.Append(text);
49+
50+
return sb;
51+
}
52+
53+
/// <summary>
54+
/// Appends a copy of the specified string followed by the default line terminator if <paramref name="condition"/> is met.
55+
/// </summary>
56+
/// <param name="sb">The StringBuilder instance to append to.</param>
57+
/// <param name="text">The string to append.</param>
58+
/// <param name="condition">The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.</param>
59+
public static StringBuilder AppendLineIf(this StringBuilder sb, string text, Func<string, bool> condition = null)
60+
{
61+
var c = condition ?? (s => !string.IsNullOrEmpty(s));
62+
63+
if (c(text))
64+
sb.AppendLine(text);
65+
66+
return sb;
67+
}
68+
69+
/// <summary>
70+
/// Appends a copy of the specified string followed by the default line terminator if <paramref name="condition"/> is met.
71+
/// </summary>
72+
/// <param name="sb">The StringBuilder instance to append to.</param>
73+
/// <param name="condition">The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.</param>
74+
public static StringBuilder AppendLineIf(this StringBuilder sb, Func<bool> condition)
75+
{
76+
if (condition())
77+
sb.AppendLine();
78+
79+
return sb;
80+
}
81+
82+
/// <summary>
83+
/// Concatenates and appends the members of a collection, using the specified separator between each member.
84+
/// </summary>
85+
/// <typeparam name="T">The type of the members of values.</typeparam>
86+
/// <param name="sb">A reference to this instance after the append operation has completed.</param>
87+
/// <param name="separator">The string to use as a separator. separator is included in the concatenated and appended strings only if values has more than one element.</param>
88+
/// <param name="values">A collection that contains the objects to concatenate and append to the current instance of the string builder.</param>
89+
/// <returns>A reference to this instance after the append operation has completed.</returns>
90+
public static StringBuilder AppendJoin<T>(this StringBuilder sb, string separator, IEnumerable<T> values)
91+
{
92+
if (sb is null)
93+
throw new ArgumentNullException(nameof(sb));
94+
if (values is null)
95+
throw new ArgumentNullException(nameof(values));
96+
97+
separator ??= string.Empty;
98+
99+
var wroteValue = false;
100+
101+
foreach (var value in values)
102+
{
103+
if (wroteValue)
104+
sb.Append(separator);
105+
106+
sb.Append(value);
107+
wroteValue = true;
108+
}
109+
110+
return sb;
111+
}
112+
113+
}
Lines changed: 11 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.Text;
45

6+
#nullable enable
7+
58
namespace FluentCommand.Extensions;
69

710
/// <summary>
@@ -16,7 +19,7 @@ public static class StringExtensions
1619
/// <returns>
1720
/// <c>true</c> if is null or empty; otherwise, <c>false</c>.
1821
/// </returns>
19-
public static bool IsNullOrEmpty(this string item)
22+
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? item)
2023
{
2124
return string.IsNullOrEmpty(item);
2225
}
@@ -28,7 +31,7 @@ public static bool IsNullOrEmpty(this string item)
2831
/// <returns>
2932
/// <c>true</c> if is null or empty; otherwise, <c>false</c>.
3033
/// </returns>
31-
public static bool IsNullOrWhiteSpace(this string item)
34+
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? item)
3235
{
3336
if (item == null)
3437
return true;
@@ -47,112 +50,19 @@ public static bool IsNullOrWhiteSpace(this string item)
4750
/// <returns>
4851
/// <c>true</c> if the specified <paramref name="value"/> is not <see cref="IsNullOrEmpty"/>; otherwise, <c>false</c>.
4952
/// </returns>
50-
public static bool HasValue(this string value)
53+
public static bool HasValue([NotNullWhen(true)] this string? value)
5154
{
5255
return !string.IsNullOrEmpty(value);
5356
}
5457

5558
/// <summary>
56-
/// Uses the string as a format
59+
/// Replaces the format item in a specified string with the string representation of a corresponding object in a specified array.
5760
/// </summary>
58-
/// <param name="format">A String reference</param>
59-
/// <param name="args">Object parameters that should be formatted</param>
60-
/// <returns>Formatted string</returns>
61-
public static string FormatWith(this string format, params object[] args)
61+
/// <param name="format">A composite format string</param>
62+
/// <param name="args">An object array that contains zero or more objects to format</param>
63+
/// <returns>A copy of format in which the format items have been replaced by the string representation of the corresponding objects in args</returns>
64+
public static string FormatWith(this string format, params object?[] args)
6265
{
63-
if (format == null)
64-
throw new ArgumentNullException("format");
65-
6666
return string.Format(format, args);
6767
}
68-
69-
/// <summary>
70-
/// Appends a copy of the specified string followed by the default line terminator to the end of the StringBuilder object.
71-
/// </summary>
72-
/// <param name="sb">The StringBuilder instance to append to.</param>
73-
/// <param name="format">A composite format string.</param>
74-
/// <param name="args">An object array that contains zero or more objects to format.</param>
75-
public static StringBuilder AppendLine(this StringBuilder sb, string format, params object[] args)
76-
{
77-
sb.AppendFormat(format, args);
78-
sb.AppendLine();
79-
return sb;
80-
}
81-
82-
/// <summary>
83-
/// Appends a copy of the specified string if <paramref name="condition"/> is met.
84-
/// </summary>
85-
/// <param name="sb">The StringBuilder instance to append to.</param>
86-
/// <param name="text">The string to append.</param>
87-
/// <param name="condition">The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.</param>
88-
public static StringBuilder AppendIf(this StringBuilder sb, string text, Func<string, bool> condition = null)
89-
{
90-
var c = condition ?? (s => !string.IsNullOrEmpty(s));
91-
92-
if (c(text))
93-
sb.Append(text);
94-
95-
return sb;
96-
}
97-
98-
/// <summary>
99-
/// Appends a copy of the specified string if <paramref name="condition"/> is met.
100-
/// </summary>
101-
/// <param name="sb">The StringBuilder instance to append to.</param>
102-
/// <param name="text">The string to append.</param>
103-
/// <param name="condition">The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.</param>
104-
public static StringBuilder AppendIf(this StringBuilder sb, string text, bool condition)
105-
{
106-
if (condition)
107-
sb.Append(text);
108-
109-
return sb;
110-
}
111-
112-
/// <summary>
113-
/// Appends a copy of the specified string followed by the default line terminator if <paramref name="condition"/> is met.
114-
/// </summary>
115-
/// <param name="sb">The StringBuilder instance to append to.</param>
116-
/// <param name="text">The string to append.</param>
117-
/// <param name="condition">The condition delegate to evaluate. If condition is null, String.IsNullOrWhiteSpace method will be used.</param>
118-
public static StringBuilder AppendLineIf(this StringBuilder sb, string text, Func<string, bool> condition = null)
119-
{
120-
var c = condition ?? (s => !string.IsNullOrEmpty(s));
121-
122-
if (c(text))
123-
sb.AppendLine(text);
124-
125-
return sb;
126-
}
127-
128-
/// <summary>
129-
/// Concatenates and appends the members of a collection, using the specified separator between each member.
130-
/// </summary>
131-
/// <typeparam name="T">The type of the members of values.</typeparam>
132-
/// <param name="sb">A reference to this instance after the append operation has completed.</param>
133-
/// <param name="separator">The string to use as a separator. separator is included in the concatenated and appended strings only if values has more than one element.</param>
134-
/// <param name="values">A collection that contains the objects to concatenate and append to the current instance of the string builder.</param>
135-
/// <returns>A reference to this instance after the append operation has completed.</returns>
136-
public static StringBuilder AppendJoin<T>(this StringBuilder sb, string separator, IEnumerable<T> values)
137-
{
138-
if (sb is null)
139-
throw new ArgumentNullException(nameof(sb));
140-
if (values is null)
141-
throw new ArgumentNullException(nameof(values));
142-
143-
separator ??= string.Empty;
144-
145-
var wroteValue = false;
146-
147-
foreach (var value in values)
148-
{
149-
if (wroteValue)
150-
sb.Append(separator);
151-
152-
sb.Append(value);
153-
wroteValue = true;
154-
}
155-
156-
return sb;
157-
}
15868
}

0 commit comments

Comments
 (0)