Skip to content
This repository has been archived by the owner on Jul 13, 2024. It is now read-only.

Commit

Permalink
Updated interfaces and readme. Incremented major version because of b…
Browse files Browse the repository at this point in the history
…reaking changes.
  • Loading branch information
gowon committed Nov 28, 2020
1 parent b2d8dd7 commit 0c8e796
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 294 deletions.
48 changes: 47 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,53 @@
# MiniProfilerContrib.Logging

[![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/MiniProfilerContrib.Logging?color=blue)](https://www.nuget.org/packages/MiniProfilerContrib.Logging)
[![Nuget](https://img.shields.io/nuget/dt/MiniProfilerContrib.Logging?color=blue)](https://www.nuget.org/packages/MiniProfilerContrib.Logging)
![build](https://github.com/gowon/MiniProfilerContrib.Logging/workflows/build/badge.svg)
[![codecov](https://codecov.io/gh/gowon/MiniProfilerContrib.Logging/branch/master/graph/badge.svg)](https://codecov.io/gh/gowon/MiniProfilerContrib.Logging)

MiniProfiler: Integration for Microsoft.Extensions.Logging
Save MiniProfiler results into a Microsoft.Extensions.Logging logger.

## Installing via NuGet

To get started install the *MiniProfilerContrib.Logging* package:

```powershell
PM> Install-Package MiniProfilerContrib.Logging
```

or

```bash
dotnet add package MiniProfilerContrib.Logging
```

## Usage

The `LoggerStorage` can accept an `ILoggerFactory` or `ILogger<MiniProfiler>`. These can be retrieved through dependency injection or by bootstrapping a logger factory.

```csharp
var loggerFactory = LoggerFactory.Create(builder =>
builder
.AddConsole()
.AddDebug()
.SetMinimumLevel(LogLevel.Trace));

var logger = loggerFactory.CreateLogger<MiniProfiler>()
```

Then, setup the `MiniProfiler` using a `LoggerStorage`, passing along the logger as well as the logging level the profiler output will be (default `LogLevel.Debug`).

```csharp
MiniProfiler.Configure(new MiniProfilerOptions
{
Storage = new LoggerStorage(logger)
});
```

And you can continue to use MiniProfiler as usual.

> See the [MiniProfiler documentation](https://miniprofiler.com/) and the `samples` folder for working examples.
## License

MIT
9 changes: 5 additions & 4 deletions samples/ConsoleAppExample/ConsoleAppExample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="2.0.30" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.2" />
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.1.0" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.112" />
<PackageReference Include="Dapper" Version="2.0.35" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.9" />
<PackageReference Include="MiniProfiler.AspNetCore" Version="4.2.1" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.113.6" />
</ItemGroup>

<ItemGroup>
Expand Down
61 changes: 32 additions & 29 deletions samples/ConsoleAppExample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,60 +1,63 @@
namespace ConsoleAppExample
using System;
using System.Data.Common;
using System.Data.SQLite;
using System.Net;
using Dapper;
using Microsoft.Extensions.Logging;
using StackExchange.Contrib.Profiling.Storage;
using StackExchange.Profiling;
using StackExchange.Profiling.Data;

namespace ConsoleAppExample
{
using System.Data.Common;
using System.Data.SQLite;
using System.Net;
using Dapper;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Debug;
using StackExchange.Contrib.Profiling.Storage;
using StackExchange.Profiling;
using StackExchange.Profiling.Data;

internal class Program
{
private static void Main(string[] args)
{
var loggerFactory = LoggerFactory.Create(builder =>
builder
.AddConsole()
.AddDebug()
.SetMinimumLevel(LogLevel.Trace));

MiniProfiler.Configure(new MiniProfilerOptions
{
Storage = new LoggingProvider(new DebugLoggerProvider().CreateLogger(nameof(ConsoleAppExample)),
LogLevel.Debug)
Storage = new LoggerStorage(loggerFactory, LogLevel.Debug)
});

var mp = MiniProfiler.StartNew("Test");
var profiler = MiniProfiler.StartNew("Sample Profile");

using (mp.Step("Level 1"))
using (var conn = GetConnection())
using (profiler.Step("Many operations"))
using (var conn = GetConnection(profiler))
{
conn.Query<long>("select 1");

using (mp.Step("Level 2"))
using (profiler.Step("Nested operation"))
{
conn.Query<long>("select 1");
}

using (var wc = new WebClient())
using (mp.CustomTiming("http", "GET https://google.com"))
using (profiler.CustomTiming("http", "GET https://google.com"))
{
wc.DownloadString("https://google.com");
}
}

mp.Stop();
profiler.Stop();

Console.ReadKey();
}

public static DbConnection GetConnection()
public static DbConnection GetConnection(MiniProfiler profiler)
{
DbConnection cnn = new SQLiteConnection("Data Source=:memory:");
var connection = new SQLiteConnection("Data Source=:memory:");

// to get profiling times, we have to wrap whatever connection we're using in a ProfiledDbConnection
// when MiniProfiler.Current is null, this connection will not record any database timings
if (MiniProfiler.Current != null)
{
cnn = new ProfiledDbConnection(cnn, MiniProfiler.Current);
}

cnn.Open();
return cnn;
// when profiler is null, this connection will not record any database timings
var profiled = new ProfiledDbConnection(connection, profiler);
profiled.Open();
return profiled;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,110 +1,112 @@
namespace StackExchange.Contrib.Profiling.Storage
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using StackExchange.Profiling;
using StackExchange.Profiling.Storage;

public class LoggingProvider : IAsyncStorage
{
private readonly Func<MiniProfiler, object> _formatter;
private readonly ILogger _logger;
private readonly LogLevel _profilingLevel;

public LoggingProvider(ILogger logger, LogLevel profilingLevel = LogLevel.Trace,
Func<MiniProfiler, object> formatter = null)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_profilingLevel = profilingLevel;
_formatter = formatter ?? (profiler =>
{
var json = JsonConvert.SerializeObject(profiler);
var obj = JsonConvert.DeserializeObject<IDictionary<string, object>>(json,
new RecursiveDictionaryConverter());
return new Dictionary<string, object> {[nameof(MiniProfiler)] = obj};
});
}

public void Save(MiniProfiler profiler)
{
if (!_logger.IsEnabled(_profilingLevel))
{
return;
}

using (_logger.BeginScope(_formatter.Invoke(MiniProfiler.Current)))
{
_logger.Log(_profilingLevel, MiniProfiler.Current.RenderPlainText());
}
}

public MiniProfiler Load(Guid id)
{
return null;
}

public async Task SaveAsync(MiniProfiler profiler)
{
Save(profiler);
await Task.CompletedTask;
}

public IEnumerable<Guid> List(
int maxResults,
DateTime? start = null,
DateTime? finish = null,
ListResultsOrder orderBy = ListResultsOrder.Descending)
{
return Enumerable.Empty<Guid>();
}

public Task<IEnumerable<Guid>> ListAsync(
int maxResults,
DateTime? start = null,
DateTime? finish = null,
ListResultsOrder orderBy = ListResultsOrder.Descending)
{
return Task.FromResult(Enumerable.Empty<Guid>());
}

public Task<MiniProfiler> LoadAsync(Guid id)
{
return Task.FromResult((MiniProfiler) null);
}

public void SetUnviewed(string user, Guid id)
{
/* no-op */
}

public Task SetUnviewedAsync(string user, Guid id)
{
return Task.CompletedTask;
}

public void SetViewed(string user, Guid id)
{
/* no-op */
}

public Task SetViewedAsync(string user, Guid id)
{
return Task.CompletedTask;
}

public List<Guid> GetUnviewedIds(string user)
{
return new List<Guid>();
}

public Task<List<Guid>> GetUnviewedIdsAsync(string user)
{
return Task.FromResult(new List<Guid>());
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using StackExchange.Profiling;
using StackExchange.Profiling.Storage;

namespace StackExchange.Contrib.Profiling.Storage
{
public class LoggerStorage : IAsyncStorage
{
private readonly Func<MiniProfiler, object> _formatter;
private readonly ILogger<MiniProfiler> _logger;
private readonly LogLevel _profilingLevel;

public LoggerStorage(ILoggerFactory loggerFactory, LogLevel profilingLevel = LogLevel.Debug,
Func<MiniProfiler, object> formatter = null) : this(loggerFactory.CreateLogger<MiniProfiler>(),
profilingLevel, formatter)
{
}

public LoggerStorage(ILogger<MiniProfiler> logger, LogLevel profilingLevel = LogLevel.Debug,
Func<MiniProfiler, object> formatter = null)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_profilingLevel = profilingLevel;
_formatter = formatter ?? (profiler =>
{
var json = JsonConvert.SerializeObject(profiler);
var obj = JsonConvert.DeserializeObject<IDictionary<string, object>>(json,
new RecursiveDictionaryConverter());
return new Dictionary<string, object> {[nameof(MiniProfiler)] = obj};
});
}

public void Save(MiniProfiler profiler)
{
if (!_logger.IsEnabled(_profilingLevel)) return;

using (_logger.BeginScope(_formatter.Invoke(profiler)))
{
_logger.Log(_profilingLevel, profiler.RenderPlainText());
}
}

public MiniProfiler Load(Guid id)
{
return null;
}

public async Task SaveAsync(MiniProfiler profiler)
{
await Task.Run(() => Save(profiler));
}

public IEnumerable<Guid> List(
int maxResults,
DateTime? start = null,
DateTime? finish = null,
ListResultsOrder orderBy = ListResultsOrder.Descending)
{
return Enumerable.Empty<Guid>();
}

public Task<IEnumerable<Guid>> ListAsync(
int maxResults,
DateTime? start = null,
DateTime? finish = null,
ListResultsOrder orderBy = ListResultsOrder.Descending)
{
return Task.FromResult(Enumerable.Empty<Guid>());
}

public Task<MiniProfiler> LoadAsync(Guid id)
{
return Task.FromResult((MiniProfiler) null);
}

public void SetUnviewed(string user, Guid id)
{
/* no-op */
}

public Task SetUnviewedAsync(string user, Guid id)
{
return Task.CompletedTask;
}

public void SetViewed(string user, Guid id)
{
/* no-op */
}

public Task SetViewedAsync(string user, Guid id)
{
return Task.CompletedTask;
}

public List<Guid> GetUnviewedIds(string user)
{
return new List<Guid>();
}

public Task<List<Guid>> GetUnviewedIdsAsync(string user)
{
return Task.FromResult(new List<Guid>());
}
}
}
Loading

0 comments on commit 0c8e796

Please sign in to comment.