Skip to content

Commit

Permalink
Better (and universal) logging (DNET-782).
Browse files Browse the repository at this point in the history
  • Loading branch information
cincuranet committed Aug 20, 2019
1 parent 9d440ac commit e9cdbaf
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 46 deletions.
Expand Up @@ -25,11 +25,14 @@
using System.Diagnostics;

using FirebirdSql.Data.Common;
using FirebirdSql.Data.Logging;

namespace FirebirdSql.Data.FirebirdClient
{
public sealed class FbCommand : DbCommand, ICloneable
{
static readonly IFbLogger Log = FbLogManager.CreateLogger(nameof(FbCommand));

#region Fields

private CommandType _commandType;
Expand Down Expand Up @@ -463,10 +466,7 @@ public override int ExecuteNonQuery()
return RecordsAffected;
}

public new FbDataReader ExecuteReader()
{
return ExecuteReader(CommandBehavior.Default);
}
public new FbDataReader ExecuteReader() => ExecuteReader(CommandBehavior.Default);
public new FbDataReader ExecuteReader(CommandBehavior behavior)
{
CheckCommand();
Expand Down Expand Up @@ -1002,8 +1002,6 @@ private void UpdateParameterValues()

private void Prepare(bool returnsSet)
{
LogCommand();

var innerConn = _connection.InnerConnection;

// Check if we have a valid transaction
Expand Down Expand Up @@ -1071,14 +1069,11 @@ private void Prepare(bool returnsSet)
}
}

private void ExecuteCommand(CommandBehavior behavior)
{
ExecuteCommand(behavior, false);
}

private void ExecuteCommand(CommandBehavior behavior) => ExecuteCommand(behavior, false);
private void ExecuteCommand(CommandBehavior behavior, bool returnsSet)
{
// Prepare statement
LogCommandExecutionIfEnabled();

Prepare(returnsSet);

if ((behavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess ||
Expand Down Expand Up @@ -1257,27 +1252,29 @@ private void CheckCommand()
}
}

[Conditional(TraceHelper.ConditionalSymbol)]
private void LogCommand()
private void LogCommandExecutionIfEnabled()
{
if (TraceHelper.HasListeners)
if (Log.IsEnabled(FbLogLevel.Debug))
{
var message = new StringBuilder();
message.AppendLine("Command:");
message.AppendLine(_commandText);
message.AppendLine("Parameters:");
if (_parameters != null)
var sb = new StringBuilder();
sb.AppendLine("Executing command:");
sb.AppendLine(_commandText);
if (FbLogManager.IsParameterLoggingEnabled)
{
foreach (FbParameter item in _parameters)
sb.AppendLine("Parameters:");
if (_parameters?.Count > 0)
{
message.AppendLine(string.Format("Name:{0}\tType:{1}\tUsed Value:{2}", item.ParameterName, item.FbDbType, (!IsNullParameterValue(item.InternalValue) ? item.InternalValue : "<null>")));
foreach (FbParameter item in _parameters)
{
sb.AppendLine(string.Format("Name:{0}\tType:{1}\tUsed Value:{2}", item.ParameterName, item.FbDbType, (!IsNullParameterValue(item.InternalValue) ? item.InternalValue : "<null>")));
}
}
else
{
sb.AppendLine("<no parameters>");
}
}
else
{
message.AppendLine("<no parameters>");
}
TraceHelper.Trace(TraceEventType.Information, message.ToString());
Log.Debug(sb.ToString());
}
}

Expand Down
@@ -0,0 +1,67 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* https://github.com/FirebirdSQL/NETProvider/blob/master/license.txt.
*
* Software distributed under the License is distributed on
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* All Rights Reserved.
*/

//$Authors = Jiri Cincura (jiri@cincura.net)

using System;
using System.Text;

namespace FirebirdSql.Data.Logging
{
public class ConsoleLoggerProvider : IFbLoggingProvider
{
readonly FbLogLevel _minimumLevel;

public ConsoleLoggerProvider(FbLogLevel minimumLevel = FbLogLevel.Info)
{
_minimumLevel = minimumLevel;
}

public IFbLogger CreateLogger(string name) => new ConsoleLogger(_minimumLevel);

sealed class ConsoleLogger : IFbLogger
{
readonly FbLogLevel _minimumLevel;

public ConsoleLogger(FbLogLevel minimumLevel)
{
_minimumLevel = minimumLevel;
}

public bool IsEnabled(FbLogLevel level)
{
return level >= _minimumLevel;
}

public void Log(FbLogLevel level, string msg, Exception exception = null)
{
if (!IsEnabled(level))
return;

var sb = new StringBuilder();
sb.Append("[");
sb.Append(level.ToString().ToUpper());
sb.Append("]");

sb.AppendLine(msg);

if (exception != null)
sb.AppendLine(exception.ToString());

Console.Error.Write(sb.ToString());
}
}
}
}
29 changes: 29 additions & 0 deletions Provider/src/FirebirdSql.Data.FirebirdClient/Logging/FbLogLevel.cs
@@ -0,0 +1,29 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* https://github.com/FirebirdSQL/NETProvider/blob/master/license.txt.
*
* Software distributed under the License is distributed on
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* All Rights Reserved.
*/

//$Authors = Jiri Cincura (jiri@cincura.net)

namespace FirebirdSql.Data.Logging
{
public enum FbLogLevel
{
Trace = 1,
Debug = 2,
Info = 3,
Warn = 4,
Error = 5,
Fatal = 6,
}
}
@@ -0,0 +1,52 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* https://github.com/FirebirdSQL/NETProvider/blob/master/license.txt.
*
* Software distributed under the License is distributed on
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* All Rights Reserved.
*/

//$Authors = Jiri Cincura (jiri@cincura.net)

using System;

namespace FirebirdSql.Data.Logging
{
public static class FbLogManager
{
public static IFbLoggingProvider Provider
{
get
{
_providerRetrieved = true;
return _provider;
}
set
{
if (_providerRetrieved)
throw new InvalidOperationException("The logging provider must be set before any action is taken");

_provider = value ?? throw new ArgumentNullException(nameof(value));
}
}

public static bool IsParameterLoggingEnabled { get; set; }

static IFbLoggingProvider _provider;
static bool _providerRetrieved;

static FbLogManager()
{
_provider = new NullLoggingProvider();
}

internal static IFbLogger CreateLogger(string name) => Provider.CreateLogger("FirebirdClient." + name);
}
}
44 changes: 44 additions & 0 deletions Provider/src/FirebirdSql.Data.FirebirdClient/Logging/IFbLogger.cs
@@ -0,0 +1,44 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* https://github.com/FirebirdSQL/NETProvider/blob/master/license.txt.
*
* Software distributed under the License is distributed on
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* All Rights Reserved.
*/

//$Authors = Jiri Cincura (jiri@cincura.net)

using System;

namespace FirebirdSql.Data.Logging
{
public interface IFbLogger
{
bool IsEnabled(FbLogLevel level);
void Log(FbLogLevel level, string msg, Exception exception = null);
}

public static class IFbLoggerExtensions
{
public static void Trace(this IFbLogger logger, string msg) => logger.Log(FbLogLevel.Trace, msg);
public static void Debug(this IFbLogger logger, string msg) => logger.Log(FbLogLevel.Debug, msg);
public static void Info(this IFbLogger logger, string msg) => logger.Log(FbLogLevel.Info, msg);
public static void Warn(this IFbLogger logger, string msg) => logger.Log(FbLogLevel.Warn, msg);
public static void Error(this IFbLogger logger, string msg) => logger.Log(FbLogLevel.Error, msg);
public static void Fatal(this IFbLogger logger, string msg) => logger.Log(FbLogLevel.Fatal, msg);

public static void Trace(this IFbLogger logger, string msg, Exception ex) => logger.Log(FbLogLevel.Trace, msg, ex);
public static void Debug(this IFbLogger logger, string msg, Exception ex) => logger.Log(FbLogLevel.Debug, msg, ex);
public static void Info(this IFbLogger logger, string msg, Exception ex) => logger.Log(FbLogLevel.Info, msg, ex);
public static void Warn(this IFbLogger logger, string msg, Exception ex) => logger.Log(FbLogLevel.Warn, msg, ex);
public static void Error(this IFbLogger logger, string msg, Exception ex) => logger.Log(FbLogLevel.Error, msg, ex);
public static void Fatal(this IFbLogger logger, string msg, Exception ex) => logger.Log(FbLogLevel.Fatal, msg, ex);
}
}
@@ -0,0 +1,24 @@
/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* https://github.com/FirebirdSQL/NETProvider/blob/master/license.txt.
*
* Software distributed under the License is distributed on
* an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* All Rights Reserved.
*/

//$Authors = Jiri Cincura (jiri@cincura.net)

namespace FirebirdSql.Data.Logging
{
public interface IFbLoggingProvider
{
IFbLogger CreateLogger(string name);
}
}
Expand Up @@ -16,32 +16,22 @@
//$Authors = Jiri Cincura (jiri@cincura.net)

using System;
using System.Diagnostics;
using System.Linq;

namespace FirebirdSql.Data.Common
namespace FirebirdSql.Data.Logging
{
internal static class TraceHelper
sealed class NullLoggingProvider : IFbLoggingProvider
{
public const string Name = "FirebirdSql.Data.FirebirdClient";
public const string ConditionalSymbol = "TRACE";
public IFbLogger CreateLogger(string name) => NullLogger.Instance;

static TraceSource _instance;

static TraceHelper()
sealed class NullLogger : IFbLogger
{
_instance = new TraceSource(Name, SourceLevels.All);
}
internal static NullLogger Instance = new NullLogger();

public static void Trace(TraceEventType eventType, string message)
{
_instance.TraceEvent(eventType, default, message);
_instance.Flush();
}
NullLogger() { }

public static bool HasListeners
{
get { return _instance.Listeners.Count > 0; }
public bool IsEnabled(FbLogLevel level) => false;

public void Log(FbLogLevel level, string msg, Exception exception = null) { }
}
}
}

0 comments on commit e9cdbaf

Please sign in to comment.