Skip to content

Commit 12a53bf

Browse files
authored
Add logs for # of rows queried and upserted (#211)
* add logs for # of rows queried and upserted * fix unit test * create logger in provider
1 parent abe38e5 commit 12a53bf

File tree

7 files changed

+31
-22
lines changed

7 files changed

+31
-22
lines changed

src/SqlAsyncCollector.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using System.Threading;
1212
using System.Threading.Tasks;
1313
using static Microsoft.Azure.WebJobs.Extensions.Sql.Telemetry.Telemetry;
14-
using Microsoft.Azure.WebJobs.Logging;
1514
using Microsoft.Data.SqlClient;
1615
using Microsoft.Extensions.Configuration;
1716
using Microsoft.Extensions.Logging;
@@ -72,11 +71,11 @@ internal class SqlAsyncCollector<T> : IAsyncCollector<T>, IDisposable
7271
/// <exception cref="ArgumentNullException">
7372
/// Thrown if either configuration or attribute is null
7473
/// </exception>
75-
public SqlAsyncCollector(IConfiguration configuration, SqlAttribute attribute, ILoggerFactory loggerFactory)
74+
public SqlAsyncCollector(IConfiguration configuration, SqlAttribute attribute, ILogger logger)
7675
{
7776
this._configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
7877
this._attribute = attribute ?? throw new ArgumentNullException(nameof(attribute));
79-
this._logger = loggerFactory?.CreateLogger(LogCategories.Bindings) ?? throw new ArgumentNullException(nameof(loggerFactory));
78+
this._logger = logger;
8079
TelemetryInstance.TrackCreate(CreateType.SqlAsyncCollector);
8180
}
8281

@@ -214,6 +213,7 @@ private async Task UpsertRowsAsync(IEnumerable<T> rows, SqlAttribute attribute,
214213
{ TelemetryMeasureName.CommandDurationMs.ToString(), commandSw.ElapsedMilliseconds }
215214
};
216215
TelemetryInstance.TrackEvent(TelemetryEventName.UpsertEnd, props, measures);
216+
this._logger.LogInformation($"Upserted {rows.Count()} row(s) into database: {connection.Database} and table: {fullTableName}.");
217217
}
218218
catch (Exception ex)
219219
{

src/SqlAsyncCollectorBuilder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ namespace Microsoft.Azure.WebJobs.Extensions.Sql
99
internal class SqlAsyncCollectorBuilder<T> : IConverter<SqlAttribute, IAsyncCollector<T>>
1010
{
1111
private readonly IConfiguration _configuration;
12-
private readonly ILoggerFactory _loggerFactory;
12+
private readonly ILogger _logger;
1313

14-
public SqlAsyncCollectorBuilder(IConfiguration configuration, ILoggerFactory loggerFactory)
14+
public SqlAsyncCollectorBuilder(IConfiguration configuration, ILogger logger)
1515
{
1616
this._configuration = configuration;
17-
this._loggerFactory = loggerFactory;
17+
this._logger = logger;
1818
}
1919

2020
IAsyncCollector<T> IConverter<SqlAttribute, IAsyncCollector<T>>.Convert(SqlAttribute attribute)
2121
{
22-
return new SqlAsyncCollector<T>(this._configuration, attribute, this._loggerFactory);
22+
return new SqlAsyncCollector<T>(this._configuration, attribute, this._logger);
2323
}
2424
}
2525
}

src/SqlBindingConfigProvider.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Microsoft.Azure.WebJobs.Host.Config;
1010
using Microsoft.Extensions.Configuration;
1111
using Microsoft.Extensions.Logging;
12+
using Microsoft.Azure.WebJobs.Logging;
1213

1314
namespace Microsoft.Azure.WebJobs.Extensions.Sql
1415
{
@@ -46,14 +47,15 @@ public void Initialize(ExtensionConfigContext context)
4647
{
4748
throw new ArgumentNullException(nameof(context));
4849
}
49-
TelemetryInstance.Initialize(this._configuration, this._loggerFactory);
50+
ILogger logger = this._loggerFactory.CreateLogger(LogCategories.Bindings);
51+
TelemetryInstance.Initialize(this._configuration, logger);
5052
#pragma warning disable CS0618 // Fine to use this for our stuff
5153
FluentBindingRule<SqlAttribute> inputOutputRule = context.AddBindingRule<SqlAttribute>();
5254
var converter = new SqlConverter(this._configuration);
5355
inputOutputRule.BindToInput(converter);
54-
inputOutputRule.BindToInput<string>(typeof(SqlGenericsConverter<string>), this._configuration);
55-
inputOutputRule.BindToCollector<OpenType>(typeof(SqlAsyncCollectorBuilder<>), this._configuration, this._loggerFactory);
56-
inputOutputRule.BindToInput<OpenType>(typeof(SqlGenericsConverter<>), this._configuration);
56+
inputOutputRule.BindToInput<string>(typeof(SqlGenericsConverter<string>), this._configuration, logger);
57+
inputOutputRule.BindToCollector<OpenType>(typeof(SqlAsyncCollectorBuilder<>), this._configuration, logger);
58+
inputOutputRule.BindToInput<OpenType>(typeof(SqlGenericsConverter<>), this._configuration, logger);
5759
}
5860
}
5961
}

src/SqlConverters.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.Data.SqlClient;
1212
using Microsoft.Extensions.Configuration;
1313
using Newtonsoft.Json;
14+
using Microsoft.Extensions.Logging;
1415

1516
namespace Microsoft.Azure.WebJobs.Extensions.Sql
1617
{
@@ -68,16 +69,20 @@ internal class SqlGenericsConverter<T> : IAsyncConverter<SqlAttribute, IEnumerab
6869
{
6970
private readonly IConfiguration _configuration;
7071

72+
private readonly ILogger _logger;
73+
7174
/// <summary>
7275
/// Initializes a new instance of the <see cref="SqlGenericsConverter<typeparamref name="T"/>"/> class.
7376
/// </summary>
7477
/// <param name="configuration"></param>
78+
/// <param name="logger">ILogger used to log information and warnings</param>
7579
/// <exception cref="ArgumentNullException">
7680
/// Thrown if the configuration is null
7781
/// </exception>
78-
public SqlGenericsConverter(IConfiguration configuration)
82+
public SqlGenericsConverter(IConfiguration configuration, ILogger logger)
7983
{
8084
this._configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
85+
this._logger = logger;
8186
TelemetryInstance.TrackCreate(CreateType.SqlGenericsConverter);
8287
}
8388

@@ -158,6 +163,7 @@ public virtual async Task<string> BuildItemFromAttributeAsync(SqlAttribute attri
158163
await connection.OpenAsync();
159164
var dataTable = new DataTable();
160165
adapter.Fill(dataTable);
166+
this._logger.LogInformation($"{dataTable.Rows.Count} row(s) queried from database: {connection.Database} using Command: {command.CommandText}");
161167
return JsonConvert.SerializeObject(dataTable);
162168
}
163169

src/Telemetry/Telemetry.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
using Microsoft.ApplicationInsights;
1111
using Microsoft.ApplicationInsights.Extensibility;
1212
using Microsoft.Extensions.Configuration;
13-
using Microsoft.Azure.WebJobs.Logging;
1413

1514
namespace Microsoft.Azure.WebJobs.Extensions.Sql.Telemetry
1615
{
@@ -43,9 +42,9 @@ public sealed class Telemetry
4342
This extension collect usage data in order to help us improve your experience. The data is anonymous and doesn't include any personal information. You can opt-out of telemetry by setting the " + TelemetryOptoutEnvVar + " environment variable or the " + TelemetryOptoutSetting + @" + app setting to '1', 'true' or 'yes';
4443
";
4544

46-
public void Initialize(IConfiguration config, ILoggerFactory loggerFactory)
45+
public void Initialize(IConfiguration config, ILogger logger)
4746
{
48-
this._logger = loggerFactory.CreateLogger(LogCategories.Bindings);
47+
this._logger = logger;
4948
this.Enabled = !(Utils.GetEnvironmentVariableAsBool(TelemetryOptoutEnvVar) || Utils.GetConfigSettingAsBool(TelemetryOptoutSetting, config));
5049
if (!this.Enabled)
5150
{

test/Unit/SqlInputBindingTests.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class SqlInputBindingTests
1919
{
2020
private static readonly Mock<IConfiguration> config = new Mock<IConfiguration>();
2121
private static readonly Mock<ILoggerFactory> loggerFactory = new Mock<ILoggerFactory>();
22+
private static readonly Mock<ILogger> logger = new Mock<ILogger>();
2223
private static readonly SqlConnection connection = new SqlConnection();
2324

2425
[Fact]
@@ -27,7 +28,7 @@ public void TestNullConfiguration()
2728
Assert.Throws<ArgumentNullException>(() => new SqlBindingConfigProvider(null, loggerFactory.Object));
2829
Assert.Throws<ArgumentNullException>(() => new SqlBindingConfigProvider(config.Object, null));
2930
Assert.Throws<ArgumentNullException>(() => new SqlConverter(null));
30-
Assert.Throws<ArgumentNullException>(() => new SqlGenericsConverter<string>(null));
31+
Assert.Throws<ArgumentNullException>(() => new SqlGenericsConverter<string>(null, logger.Object));
3132
}
3233

3334
[Fact]
@@ -219,7 +220,7 @@ public void TestWellformedParametersString()
219220
public async void TestWellformedDeserialization()
220221
{
221222
var arg = new SqlAttribute(string.Empty);
222-
var converter = new Mock<SqlGenericsConverter<TestData>>(config.Object);
223+
var converter = new Mock<SqlGenericsConverter<TestData>>(config.Object, logger.Object);
223224
string json = "[{ \"ID\":1,\"Name\":\"Broom\",\"Cost\":32.5,\"Timestamp\":\"2019-11-22T06:32:15\"},{ \"ID\":2,\"Name\":\"Brush\",\"Cost\":12.3," +
224225
"\"Timestamp\":\"2017-01-27T03:13:11\"},{ \"ID\":3,\"Name\":\"Comb\",\"Cost\":100.12,\"Timestamp\":\"1997-05-03T10:11:56\"}]";
225226
converter.Setup(_ => _.BuildItemFromAttributeAsync(arg)).ReturnsAsync(json);
@@ -256,7 +257,7 @@ public async void TestWellformedDeserialization()
256257
public async void TestMalformedDeserialization()
257258
{
258259
var arg = new SqlAttribute(string.Empty);
259-
var converter = new Mock<SqlGenericsConverter<TestData>>(config.Object);
260+
var converter = new Mock<SqlGenericsConverter<TestData>>(config.Object, logger.Object);
260261

261262
// SQL data is missing a field
262263
string json = "[{ \"ID\":1,\"Name\":\"Broom\",\"Timestamp\":\"2019-11-22T06:32:15\"}]";

test/Unit/SqlOutputBindingTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,24 @@
44
using System;
55
using System.Threading.Tasks;
66
using Microsoft.Extensions.Configuration;
7-
using Microsoft.Extensions.Logging.Abstractions;
87
using Moq;
98
using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common;
109
using Xunit;
10+
using Microsoft.Extensions.Logging;
1111

1212
namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Unit
1313
{
1414
public class SqlOutputBindingTests
1515
{
1616
private static readonly Mock<IConfiguration> config = new Mock<IConfiguration>();
17+
private static readonly Mock<ILogger> logger = new Mock<ILogger>();
1718

1819
[Fact]
1920
public void TestNullCollectorConstructorArguments()
2021
{
2122
var arg = new SqlAttribute(string.Empty);
22-
Assert.Throws<ArgumentNullException>(() => new SqlAsyncCollector<string>(config.Object, null, NullLoggerFactory.Instance));
23-
Assert.Throws<ArgumentNullException>(() => new SqlAsyncCollector<string>(null, arg, NullLoggerFactory.Instance));
23+
Assert.Throws<ArgumentNullException>(() => new SqlAsyncCollector<string>(config.Object, null, logger.Object));
24+
Assert.Throws<ArgumentNullException>(() => new SqlAsyncCollector<string>(null, arg, logger.Object));
2425
}
2526

2627
[Fact]
@@ -29,7 +30,7 @@ public async Task TestAddAsync()
2930
// Really a pretty silly test. Just confirms that the SQL connection is only opened when FlushAsync is called,
3031
// because otherwise we would get an exception in AddAsync (since the SQL connection in the wrapper is null)
3132
var arg = new SqlAttribute(string.Empty);
32-
var collector = new SqlAsyncCollector<TestData>(config.Object, arg, NullLoggerFactory.Instance);
33+
var collector = new SqlAsyncCollector<TestData>(config.Object, arg, logger.Object);
3334
var data = new TestData
3435
{
3536
ID = 1,

0 commit comments

Comments
 (0)