Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Alternate ILoggerProvider-based logging API #269

Merged
merged 4 commits into from
Nov 30, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions doc/faq/README.md
Original file line number Diff line number Diff line change
@@ -5,7 +5,24 @@
Normally you should use one `ISession` instance per application. You should share that instance between classes within
your application.

## How can I enable tracing in the driver?
## How can I enable logging in the driver?

The driver allows you to plug in any [`ILoggerProvider`][logging-api] implementation, like [NLog][nlog] and
[Serilog][serilog] implementations.

You should set the provider before initializing the cluster, using the `Diagnostics` class:

```csharp
// Use the provider you prefer, in this case NLog
ILoggerProvider provider = new NLogLoggerProvider();
// Add it before initializing the Cluster
Cassandra.Diagnostics.AddLoggerProvider(provider);
```

You can configure the log levels you want to output using the provider API.

Alternatively, if you don't want to use a `ILoggerProvider` implementation, the driver can expose log events using
the .NET Tracing API.

```csharp
// Specify the minimum trace level you want to see
@@ -18,12 +35,16 @@ Trace.Listeners.Add(new ConsoleTraceListener());

It depends on the size of the requests and the number of tables affected by the BATCH. Large batches can
cause a lot of stress on the coordinator. Consider that Cassandra batches are not suitable for bulk loading, there
are dedicated tools for that. batches allow you to group related updates in a single request, so keep the BATCH size
are dedicated tools for that. Batches allow you to group related updates in a single request, so keep the BATCH size
small (in the order of tens).

Starting from Cassandra version 2.0.8, the node issues a warning if the batch size is greater than 5K.

## What is the best way to retrieve multiple rows that contain large-sized blobs?

You can decrease the number of rows retrieved per page. By using the `SetPageSize()` method on a statement, you
instruct the driver to retrieve fewer rows per request (the default is 5000).
instruct the driver to retrieve fewer rows per request (the default is 5000).

[logging-api]: https://github.com/aspnet/Logging
[nlog]: https://github.com/NLog/NLog.Extensions.Logging
[serilog]: https://github.com/serilog/serilog-extensions-logging
1 change: 1 addition & 0 deletions src/Cassandra.Tests/Cassandra.Tests.csproj
Original file line number Diff line number Diff line change
@@ -74,6 +74,7 @@
<Compile Include="CqlParameterTest.cs" />
<Compile Include="LocalDateTests.cs" />
<Compile Include="LocalTimeTests.cs" />
<Compile Include="LoggingTests.cs" />
<Compile Include="Mapping\AttributeBasedTypeDefinitionTests.cs" />
<Compile Include="Mapping\BatchTests.cs" />
<Compile Include="Mapping\DeleteTests.cs" />
71 changes: 71 additions & 0 deletions src/Cassandra.Tests/LoggingTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using NUnit.Framework;

namespace Cassandra.Tests
{
[TestFixture]
public class LoggingTests
{
[Test]
public void FactoryBasedLoggerHandler_Methods_Not_Throw()
{
UseAllMethods(new Logger.FactoryBasedLoggerHandler(typeof(int)));
}

[Test]
public void FactoryBasedLoggerHandler_Methods_Should_Output_To_Trace()
{
var originalLevel = Diagnostics.CassandraTraceSwitch.Level;
Diagnostics.CassandraTraceSwitch.Level = TraceLevel.Verbose;
var listener = new TestTraceListener();
Trace.Listeners.Add(listener);
UseAllMethods(new Logger.TraceBasedLoggerHandler(typeof(int)));
Trace.Listeners.Remove(listener);
Assert.AreEqual(6, listener.Messages.Count);
Diagnostics.CassandraTraceSwitch.Level = originalLevel;
var expectedMessages = new[]
{
"Test exception 1",
"Message 1",
"Message 2 Param1",
"Message 3 Param2",
"Message 4 Param3",
"Message 5 Param4"
};
var messages = listener.Messages.Keys.OrderBy(k => k).Select(k => listener.Messages[k]).ToArray();
for (var i = 0; i < expectedMessages.Length; i++)
{
StringAssert.Contains(expectedMessages[i], messages[i]);
}
}

private void UseAllMethods(Logger.ILoggerHandler loggerHandler)
{
loggerHandler.Error(new Exception("Test exception 1"));
loggerHandler.Error("Message 1", new Exception("Test exception 1"));
loggerHandler.Error("Message 2 {0}", "Param1");
loggerHandler.Info("Message 3 {0}", "Param2");
loggerHandler.Verbose("Message 4 {0}", "Param3");
loggerHandler.Warning("Message 5 {0}", "Param4");
}

private class TestTraceListener : TraceListener
{
public readonly ConcurrentDictionary<int, string> Messages = new ConcurrentDictionary<int, string>();
private int _counter = -1;

public override void Write(string message)
{
}

public override void WriteLine(string message)
{
Messages.AddOrUpdate(Interlocked.Increment(ref _counter), message, (k, v) => message);
}
}
}
}
9 changes: 9 additions & 0 deletions src/Cassandra/Cassandra.csproj
Original file line number Diff line number Diff line change
@@ -45,9 +45,18 @@
<HintPath>..\packages\lz4net.1.0.10.93\lib\net4-client\LZ4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Extensions.Logging">
<HintPath>..\packages\Microsoft.Extensions.Logging.1.0.0\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.1.0.0\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
5 changes: 4 additions & 1 deletion src/Cassandra/Cassandra.project.json
Original file line number Diff line number Diff line change
@@ -8,11 +8,14 @@
"System": "",
"System.Data": "",
"System.Numerics": "",
"System.Runtime": "",
"System.Xml": ""
}
}
},
"dependencies": {
"lz4net": "1.0.10.93"
"lz4net": "1.0.10.93",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Abstractions": "1.0.0"
}
}
41 changes: 36 additions & 5 deletions src/Cassandra/Diagnostics.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright (C) 2012-2014 DataStax Inc.
// Copyright (C) 2012-2016 DataStax Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -15,22 +15,38 @@
//

using System.Diagnostics;
using Microsoft.Extensions.Logging;

namespace Cassandra
{
/// <summary>
/// Provides a set of methods and properties related to logging in the driver.
/// </summary>
public static class Diagnostics
{
/// <summary>
/// Specifies what messages should be passed to the output log.
/// <para></para>
/// Determines if a <see cref="ILoggerFactory"/> API should be used to obtain a instance of logger.
/// </summary>
internal static volatile bool UseLoggerFactory;

internal static readonly ILoggerFactory LoggerFactory = new LoggerFactory();

/// <summary>
/// Specifies what messages should be passed to the output log when using the <see cref="Trace"/> API.
/// <para></para>
/// <para><value>TraceLevel.Off</value> - Output no tracing messages.</para>
/// <para><value>TraceLevel.Error</value> - Output error-handling messages.</para>
/// <para><value>TraceLevel.Warning</value> - Output warnings and error-handling messages.</para>
/// <para><value>TraceLevel.Info</value> - Output informational messages, warnings, and error-handling messages.</para>
/// <para><value>TraceLevel.Verbose</value> - Output all debugging and tracing messages.</para>
/// </summary>
public static readonly TraceSwitch CassandraTraceSwitch = new TraceSwitch("TraceSwitch",
"This switch lets the user choose which kind of messages should be included in log.");
/// <remarks>
/// Consider using <c>Microsoft.Extensions.Logging</c> API instead by adding a <see cref="ILoggerProvider"/>
/// using the <see cref="AddLoggerProvider(ILoggerProvider)"/> method.
/// </remarks>
/// <seealso cref="AddLoggerProvider"/>
public static readonly TraceSwitch CassandraTraceSwitch = new TraceSwitch(
"TraceSwitch", "This switch lets the user choose which kind of messages should be included in log.");

/// <summary>
/// Defines if exception StackTrace information should be printed by trace logger.
@@ -43,5 +59,20 @@ public static class Diagnostics
/// <para>Default value is <value>false</value>.</para>
/// </summary>
public static bool CassandraPerformanceCountersEnabled { get; set; }

/// <summary>
/// Adds a <see cref="ILoggerProvider" /> to the logger factory used by the driver.
/// <para>
/// Be sure to call this method before initializing the <see cref="ICluster"/> to ensure that
/// <see cref="ILoggerFactory"/> API is used as driver logging mechanism instead of
/// <see cref="Trace"/>.
/// </para>
/// </summary>
/// <param name="provider">The logger provider to add to the logger factory</param>
public static void AddLoggerProvider(ILoggerProvider provider)
{
UseLoggerFactory = true;
LoggerFactory.AddProvider(provider);
}
}
}
Loading