• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / FluentCommand / 36888666826

01 Oct 2026 04:00PM UTC coverage: 61.179% (-4.7%) from 65.903%
36888666826

push

github

pwelter34
Improve MERGE SQL generation and literals

1624 of 3516 branches covered (46.19%)

Branch coverage included in aggregate %.

49 of 70 new or added lines in 1 file covered. (70.0%)

373 existing lines in 32 files now uncovered.

5422 of 8001 relevant lines covered (67.77%)

292.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.25
/src/FluentCommand/DataQueryLogger.cs
1
using System.Data;
2
using System.Text;
3

4
using FluentCommand.Extensions;
5
using FluentCommand.Internal;
6

7
using Microsoft.Extensions.Logging;
8

9
namespace FluentCommand;
10

11
/// <summary>
12
/// A class for logging queries
13
/// </summary>
14
/// <seealso cref="FluentCommand.IDataQueryLogger" />
15
public partial class DataQueryLogger : IDataQueryLogger
16
{
17
    /// <summary>
18
    /// The default maximum formatted query length to write to the log.
19
    /// </summary>
20
    public const int DefaultMaxQueryLength = 32 * 1024;
21

22
    /// <summary>
23
    /// The default maximum parameter value length to write to the log.
24
    /// </summary>
25
    public const int DefaultMaxParameterLength = 1024;
26

27

28
    /// <summary>
29
    /// Initializes a new instance of the <see cref="DataQueryLogger"/> class.
30
    /// </summary>
31
    /// <param name="logger">The logger.</param>
32
    public DataQueryLogger(ILogger<DataQueryLogger> logger)
33
        : this(logger, DefaultMaxQueryLength, DefaultMaxParameterLength)
3 ✔
34
    {
35
    }
3 ✔
36

37
    /// <summary>
38
    /// Initializes a new instance of the <see cref="DataQueryLogger"/> class.
39
    /// </summary>
40
    /// <param name="logger">The logger.</param>
41
    /// <param name="maxQueryLength">The maximum formatted query length to write to the log.</param>
42
    /// <param name="maxParameterLength">The maximum parameter value length to write to the log.</param>
43
    public DataQueryLogger(ILogger<DataQueryLogger> logger, int maxQueryLength, int maxParameterLength)
3 ✔
44
    {
45
        ArgumentOutOfRangeException.ThrowIfLessThan(maxQueryLength, 1);
3 ✔
46
        ArgumentOutOfRangeException.ThrowIfLessThan(maxParameterLength, 1);
3 ✔
47

48
        Logger = logger ?? throw new ArgumentNullException(nameof(logger));
3 !
49
        MaxQueryLength = maxQueryLength;
3 ✔
50
        MaxParameterLength = maxParameterLength;
3 ✔
51
    }
3 ✔
52

53

54
    /// <summary>
55
    /// Gets the logger used to write command log messages.
56
    /// </summary>
57
    protected ILogger Logger { get; }
58

59
    /// <summary>
60
    /// Gets the maximum formatted query length to write to the log.
61
    /// </summary>
62
    protected int MaxQueryLength { get; }
63

64
    /// <summary>
65
    /// Gets the maximum parameter value length to write to the log.
66
    /// </summary>
67
    protected int MaxParameterLength { get; }
68

69

70
    /// <summary>
71
    /// Log the current specified <paramref name="command" />
72
    /// </summary>
73
    /// <param name="command">The command to log.</param>
74
    /// <param name="duration">The execution duration.</param>
75
    /// <param name="exception">The exception thrown when executing the command.</param>
76
    /// <param name="state">The state used to control logging.</param>
77
    /// <exception cref="System.ArgumentNullException">command</exception>
78
    public virtual void LogCommand(IDbCommand command, TimeSpan duration, Exception? exception = null, object? state = null)
79
    {
80
        ArgumentNullException.ThrowIfNull(command);
265 ✔
81

82
        var logLevel = exception == null ? LogLevel.Debug : LogLevel.Error;
265 ✔
83
        if (!Logger.IsEnabled(logLevel))
265 !
UNCOV
84
            return;
×
85

86
        var elapsed = duration.TotalMilliseconds;
265 ✔
87
        var commandType = command.CommandType;
265 ✔
88
        var commandTimeout = command.CommandTimeout;
265 ✔
89
        var commandText = FormatCommand(command);
265 ✔
90

91
        if (exception == null)
265 ✔
92
            LogCommand(Logger, elapsed, commandType, commandTimeout, commandText);
263 ✔
93
        else
94
            LogError(Logger, elapsed, commandType, commandTimeout, commandText, exception);
2 ✔
95
    }
2 ✔
96

97

98
    private string FormatCommand(IDbCommand command)
99
    {
100
        var commandText = command.CommandText ?? string.Empty;
265 !
101

102
        // get start and end of the trimmed command text
103
        GetTrimmedRange(commandText, out var commandTextStart, out var commandTextLength);
265 ✔
104

105
        // don't log really long queries
106
        if (commandTextLength > MaxQueryLength || commandTextLength == 0)
265 !
UNCOV
107
            return string.Empty;
×
108

109
        var builder = StringBuilderCache.Acquire(commandTextLength + Environment.NewLine.Length);
265 ✔
110

111
        // new line to wrap from existing log message
112
        builder.AppendLine();
265 ✔
113
        builder.Append(commandText, commandTextStart, commandTextLength);
265 ✔
114

115
        AppendParameters(builder, command);
265 ✔
116

117
        return StringBuilderCache.ToString(builder);
265 ✔
118
    }
119

120
    private void AppendParameters(StringBuilder builder, IDbCommand command)
121
    {
122
        if (command.Parameters == null || command.Parameters.Count == 0)
265 !
123
            return;
45 ✔
124

125
        foreach (IDataParameter parameter in command.Parameters)
1,576 ✔
126
        {
127
            int precision = 0;
568 ✔
128
            int scale = 0;
568 ✔
129
            int size = 0;
568 ✔
130

131
            if (parameter is IDbDataParameter dataParameter)
568 ✔
132
            {
133
                precision = dataParameter.Precision;
568 ✔
134
                scale = dataParameter.Scale;
568 ✔
135
                size = dataParameter.Size;
568 ✔
136
            }
137

138
            if (builder.Length > 0)
568 ✔
139
                builder.AppendLine();
568 ✔
140

141
            builder
568 ✔
142
                .Append("-- ")
568 ✔
143
                .Append(parameter.ParameterName)
568 ✔
144
                .Append(": ")
568 ✔
145
                .Append(parameter.Direction)
568 ✔
146
                .Append(' ')
568 ✔
147
                .Append(parameter.DbType)
568 ✔
148
                .Append("(Size=")
568 ✔
149
                .Append(size)
568 ✔
150
                .Append("; Precision=")
568 ✔
151
                .Append(precision)
568 ✔
152
                .Append("; Scale=")
568 ✔
153
                .Append(scale)
568 ✔
154
                .Append(") [")
568 ✔
155
                .AppendTruncated(parameter.Value, MaxParameterLength)
568 ✔
156
                .Append(']');
568 ✔
157
        }
158
    }
220 ✔
159

160

161
    private static void GetTrimmedRange(string text, out int startIndex, out int length)
162
    {
163
        var endIndex = text.Length;
265 ✔
164
        startIndex = 0;
265 ✔
165

166
        while (startIndex < endIndex && IsLineBreak(text[startIndex]))
265 !
UNCOV
167
            startIndex++;
×
168

169
        while (endIndex > startIndex && IsLineBreak(text[endIndex - 1]))
347 !
170
            endIndex--;
82 ✔
171

172
        length = endIndex - startIndex;
265 ✔
173
    }
265 ✔
174

175
    private static bool IsLineBreak(char value) => value == '\r' || value == '\n';
612 !
176

177

178
    [LoggerMessage(0, LogLevel.Debug, "Executed DbCommand ({Elapsed} ms) [CommandType='{CommandType}', CommandTimeout='{CommandTimeout}']{CommandText}")]
179
    private static partial void LogCommand(ILogger logger, double elapsed, CommandType commandType, int commandTimeout, string commandText);
180

181
    [LoggerMessage(1, LogLevel.Error, "Error Executing DbCommand ({Elapsed} ms) [CommandType='{CommandType}', CommandTimeout='{CommandTimeout}']{CommandText}")]
182
    private static partial void LogError(ILogger logger, double elapsed, CommandType commandType, int commandTimeout, string commandText, Exception exception);
183
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc