Skip to content
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
<Compile Include="TestHelpers\SelfCleaningDirectory.cs" />
<Compile Include="TestHelpers\SignatureExtensions.cs" />
<Compile Include="TestHelpers\SkippableFactAttribute.cs" />
<Compile Include="LogFixture.cs" />
<Compile Include="TreeDefinitionFixture.cs" />
<Compile Include="TreeFixture.cs" />
<Compile Include="UnstageFixture.cs" />
Expand Down
40 changes: 40 additions & 0 deletions LibGit2Sharp.Tests/LogFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using LibGit2Sharp;
using LibGit2Sharp.Core;
using Xunit;

namespace LibGit2Sharp.Tests
{
public class LogFixture
{
[Fact]
public void CanEnableAndDisableLogging()
{
// Setting logging produces a log message at level Info,
// ensure that we catch it.
LogLevel level = LogLevel.None;
string message = null;

GlobalSettings.LogConfiguration = new LogConfiguration(LogLevel.Trace, (l, m) => { level = l; message = m; });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also assert that a message isn't logged if new LogConfiguration(LogLevel.Warn, ...) is set?


Assert.Equal(LogLevel.Info, level);
Assert.Equal("Logging enabled at level Trace", message);

// Configuring at Warning and higher means that the
// message at level Info should not be produced.
level = LogLevel.None;
message = null;

GlobalSettings.LogConfiguration = new LogConfiguration(LogLevel.Warning, (l, m) => { level = l; message = m; });

Assert.Equal(LogLevel.None, level);
Assert.Equal(null, message);

// Similarly, turning logging off should produce no messages.
GlobalSettings.LogConfiguration = LogConfiguration.None;

Assert.Equal(LogLevel.None, level);
Assert.Equal(null, message);
}
}
}
5 changes: 5 additions & 0 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1496,6 +1496,11 @@ internal static extern int git_tag_delete(
[DllImport(libgit2)]
internal static extern void git_threads_shutdown();

internal delegate void git_trace_cb(LogLevel level, IntPtr message);

[DllImport(libgit2)]
internal static extern int git_trace_set(LogLevel level, git_trace_cb trace_cb);

internal delegate int git_transfer_progress_callback(ref GitTransferProgress stats, IntPtr payload);

internal delegate int git_transport_cb(out IntPtr transport, IntPtr remote, IntPtr payload);
Expand Down
13 changes: 13 additions & 0 deletions LibGit2Sharp/Core/Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2951,6 +2951,19 @@ public static GitObjectType git_tag_target_type(GitObjectSafeHandle tag)

#endregion

#region git_trace_

public static void git_trace_set(LogLevel level, NativeMethods.git_trace_cb callback)
{
using (ThreadAffinity())
{
int res = NativeMethods.git_trace_set(level, callback);
Ensure.ZeroResult(res);
}
}

#endregion

#region git_transport_

public static void git_transport_register(String prefix, IntPtr transport_cb, IntPtr param)
Expand Down
36 changes: 36 additions & 0 deletions LibGit2Sharp/GlobalSettings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using LibGit2Sharp.Core;
using LibGit2Sharp.Handlers;

namespace LibGit2Sharp
{
Expand All @@ -10,6 +11,8 @@ public static class GlobalSettings
{
private static readonly Lazy<Version> version = new Lazy<Version>(Version.Build);

private static LogConfiguration logConfiguration = LogConfiguration.None;

/// <summary>
/// Returns all the optional features that were compiled into
/// libgit2.
Expand Down Expand Up @@ -84,5 +87,38 @@ public static void UnregisterSmartSubtransport<T>(SmartSubtransportRegistration<
Proxy.git_transport_unregister(registration.Scheme);
registration.Free();
}

/// <summary>
/// Registers a new <see cref="LogConfiguration"/> to receive
/// information logging information from libgit2 and LibGit2Sharp.
///
/// Note that this configuration is global to an entire process
/// and does not honor application domains.
/// </summary>
public static LogConfiguration LogConfiguration
{
set
{
Ensure.ArgumentNotNull(value, "value");

logConfiguration = value;

if (logConfiguration.Level == LogLevel.None)
{
Proxy.git_trace_set(0, null);
}
else
{
Proxy.git_trace_set(value.Level, value.GitTraceHandler);

Log.Write(LogLevel.Info, "Logging enabled at level {0}", value.Level);
}
}

get
{
return logConfiguration;
}
}
}
}
8 changes: 8 additions & 0 deletions LibGit2Sharp/Handlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,12 @@ public enum PackBuilderStage
/// </summary>
Deltafying
}

/// <summary>
/// Delegate definition for logging. This callback will be used to
/// write logging messages in libgit2 and LibGit2Sharp.
/// </summary>
/// <param name="level">The level of the log message.</param>
/// <param name="message">The log message.</param>
public delegate void LogHandler(LogLevel level, string message);
}
3 changes: 3 additions & 0 deletions LibGit2Sharp/LibGit2Sharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@
<Compile Include="StageOptions.cs" />
<Compile Include="StatusOptions.cs" />
<Compile Include="SimilarityOptions.cs" />
<Compile Include="Log.cs" />
<Compile Include="LogConfiguration.cs" />
<Compile Include="LogLevel.cs" />
<Compile Include="UnbornBranchException.cs" />
<Compile Include="LockedFileException.cs" />
<Compile Include="Core\GitRepositoryInitOptions.cs" />
Expand Down
30 changes: 30 additions & 0 deletions LibGit2Sharp/Log.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Runtime.CompilerServices;
using LibGit2Sharp.Core;

namespace LibGit2Sharp
{
internal class Log

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

internal class Log
{
    private static bool IsEnabled(LogConfiguration configuration, LogLevel level)
    {
        return (configuration.Level != LogLevel.None && configuration.Level >= level);   
    }

    internal static bool IsEnabled(LogLevel level)
    {
        return IsEnabled(GlobalSettings.LogConfiguration);
    }

    internal static void Write(LogLevel level, string message, params object[] args)
    {
        if (!IsEnabled(GlobalSettings.LogConfiguration))
        {
            return;
        }

        configuration.Handler(level, string.Format(message, args));
    }
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the proposal is here...doesn't seem like this code would work?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.doesn't seem like this code would work?

@dahlbyk You're right. I forgot to declare a local configuration in Write(LogLevel level, string message, params object[] args), but @ethomson fixed my mistake as part of its commit.

Not sure what the proposal is here...

Note: This comment has been made on a previous version of this Log class.

The goal was to avoid the duplicated use of (configuration.Level != LogLevel.None && configuration.Level >= level) (which was previously present in both IsEnabled and Write), by introducing a IsEnabled(LogConfiguration configuration, LogLevel level) method.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying... I thought the current code looked pretty good. 😀

{
private static bool IsEnabled(LogConfiguration configuration, LogLevel level)
{
return (configuration.Level != LogLevel.None && configuration.Level >= level);
}

internal static bool IsEnabled(LogLevel level)
{
return IsEnabled(GlobalSettings.LogConfiguration, level);
}

internal static void Write(LogLevel level, string message, params object[] args)
{
LogConfiguration configuration = GlobalSettings.LogConfiguration;

if (!IsEnabled(configuration, level))
{
return;
}

configuration.Handler(level, string.Format(message, args));
}
}
}
45 changes: 45 additions & 0 deletions LibGit2Sharp/LogConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using LibGit2Sharp.Core;
using LibGit2Sharp.Handlers;

namespace LibGit2Sharp
{
/// <summary>
/// Logging and tracing configuration for libgit2 and LibGit2Sharp.
/// </summary>
public sealed class LogConfiguration
{
/// <summary>
/// The default logging configuration, which performs no logging at all.
/// </summary>
public static readonly LogConfiguration None = new LogConfiguration { Level = LogLevel.None };

/// <summary>
/// Creates a new logging configuration to call the given
/// delegate when logging occurs at the given level.
/// </summary>
/// <param name="level">Level to log at</param>
/// <param name="handler">Handler to call when logging occurs</param>
public LogConfiguration(LogLevel level, LogHandler handler)
{
Ensure.ArgumentConformsTo<LogLevel>(level, (t) => { return (level != LogLevel.None); }, "level");
Ensure.ArgumentNotNull(handler, "handler");

Level = level;
Handler = handler;
}

private LogConfiguration()
{
}

internal LogLevel Level { get; private set; }
internal LogHandler Handler { get; private set; }

internal void GitTraceHandler(LogLevel level, IntPtr msg)
{
string message = LaxUtf8Marshaler.FromNative(msg);
Handler(level, message);
}
}
}
50 changes: 50 additions & 0 deletions LibGit2Sharp/LogLevel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LibGit2Sharp
{
/// <summary>
/// Available logging levels. When logging is enabled at a particular
/// level, callers will be provided logging at the given level and all
/// lower levels.
/// </summary>
public enum LogLevel
{
/// <summary>
/// No logging will be provided.
/// </summary>
None = 0,

/// <summary>
/// Severe errors that may impact the program's execution.
/// </summary>
Fatal = 1,

/// <summary>
/// Errors that do not impact the program's execution.
/// </summary>
Error = 2,

/// <summary>
/// Warnings that suggest abnormal data.
/// </summary>
Warning = 3,

/// <summary>
/// Informational messages about program execution.
/// </summary>
Info = 4,

/// <summary>
/// Detailed data that allows for debugging.
/// </summary>
Debug = 5,

/// <summary>
/// Tracing is exceptionally detailed debugging data.
/// </summary>
Trace = 6,
}
}