Skip to content

Commit 9bfc67d

Browse files
authored
Removed dependency from Serilog.Sinks.Http + implemented LokiGzipHttpClient + more tests & bugfixes (#33)
* Timer + Batch (+tests) & LokiClient draft * ExponentialBackoffScheduler + tests * More draft * Implemented sink + batch formatter + fixes * Removed dependency to Serilog.Sinks.Http * Bugfix * Utils tests + regroup of existing ones * Deleted redundant fixture * Deleted redundant folder * Fixed doc * Implemented client with gzip compression * Updated README.MD * Added license headers
1 parent cf3fa21 commit 9bfc67d

File tree

52 files changed

+2238
-1176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2238
-1176
lines changed

README.md

Lines changed: 151 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,151 @@
1-
# Serilog.Sinks.Grafana.Loki
2-
3-
[![Build status](https://github.com/mishamyte/serilog-sinks-grafana-loki/workflows/CI/badge.svg)](https://github.com/mishamyte/serilog-sinks-grafana-loki/actions?query=workflow%3ACI)
4-
[![NuGet Version](https://img.shields.io/nuget/v/Serilog.Sinks.Grafana.Loki)](https://www.nuget.org/packages/Serilog.Sinks.Grafana.Loki)
5-
[![Documentation](https://img.shields.io/badge/docs-wiki-blueviolet.svg)](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki)
6-
7-
## Table of contents
8-
- [What is this sink and Loki?](#what-is-this)
9-
- [Features](#features)
10-
- [Comparison with other Loki sinks](#comparison)
11-
- [Breaking changes](#breaking-changes)
12-
- [Quickstart](#quickstart)
13-
- [Custom HTTP Client](#custom-http-client)
14-
- [Sending json content to Loki](#sending-json-content-to-loki)
15-
- [Inspiration and Credits](#inspiration-and-credits)
16-
17-
## What is this sink and Loki?
18-
19-
The Serilog Grafana Loki sink project is a sink (basically a writer) for the Serilog logging framework. Structured log events are written to sinks and each sink is responsible for writing it to its own backend, database, store etc. This sink delivers the data to Grafana Loki, a horizontally-scalable, highly-available, multi-tenant log aggregation system. It allows you to use Grafana for visualizing your logs.
20-
21-
You can find more information about what Loki is over on [Grafana's website here](https://grafana.com/loki).
22-
23-
## Features:
24-
- Formats and batches log entries to Loki via HTTP (using actual API)
25-
- Global and contextual labels support
26-
- Labels filtration modes
27-
- Integration with Serilog.Settings.Configuration
28-
- Customizable HTTP client
29-
- Using fast System.Text.Json library for serialization
30-
31-
Coming soon:
32-
- Improve durable mode (keep labels & etc)
33-
34-
## Comparison
35-
Features comparison table could be found [here](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki/Comparison-with-another-Loki-sinks)
36-
37-
## Breaking changes
38-
The list of breaking changes could be found [here](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki/Breaking-changes)
39-
40-
## Quickstart
41-
The `Serilog.Sinks.Grafana.Loki` NuGet [package could be found here](https://www.nuget.org/packages/Serilog.Sinks.Grafana.Loki). Alternatively you can install it via one of the following commands below:
42-
43-
NuGet command:
44-
```bash
45-
Install-Package Serilog.Sinks.Grafana.Loki
46-
```
47-
.NET Core CLI:
48-
```bash
49-
dotnet add package Serilog.Sinks.Grafana.Loki
50-
```
51-
52-
In the following example, the sink will send log events to Loki available on `http://localhost:3100`
53-
```csharp
54-
ILogger logger = new LoggerConfiguration()
55-
.WriteTo.GrafanaLoki(
56-
"http://localhost:3100")
57-
.CreateLogger();
58-
59-
logger.Information("The god of the day is {@God}", odin)
60-
```
61-
62-
Used in conjunction with [Serilog.Settings.Configuration](https://github.com/serilog/serilog-settings-configuration) the same sink can be configured in the following way:
63-
64-
```json
65-
{
66-
"Serilog": {
67-
"Using": [
68-
"Serilog.Sinks.Grafana.Loki"
69-
],
70-
"MinimumLevel": {
71-
"Default": "Debug"
72-
},
73-
"WriteTo": [
74-
{
75-
"Name": "GrafanaLoki",
76-
"Args": {
77-
"uri": "http://localhost:3100",
78-
"labels": [
79-
{
80-
"key": "app",
81-
"value": "web_app"
82-
}
83-
],
84-
"outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss} [{Level:u3}] [{ThreadId}] {Message}{NewLine}{Exception}"
85-
}
86-
}
87-
]
88-
}
89-
}
90-
```
91-
92-
Description of parameters and configuration details could be found [here](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki/Application-settings).
93-
94-
### Custom HTTP Client
95-
Serilog.Loki.Grafana.Loki is built on top of the popular [Serilog.Sinks.Http](https://github.com/FantasticFiasco/serilog-sinks-http) library.
96-
In order to use a custom HttpClient you can extend the default HttpClient (`Serilog.Sinks.Grafana.Loki.DefaultLokiHttpClient`), or create one implementing `Serilog.Sinks.Grafana.Loki.ILokiHttpClient` (which extends `Serilog.Sinks.Http.IHttpClient`).
97-
98-
```csharp
99-
// CustomHttpClient.cs
100-
101-
public class CustomHttpClient : DefaultLokiHttpClient
102-
{
103-
public override Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
104-
{
105-
return base.PostAsync(requestUri, content);
106-
}
107-
}
108-
```
109-
```csharp
110-
// Usage
111-
112-
Log.Logger = new LoggerConfiguration()
113-
.WriteTo.GrafanaLoki(
114-
"http://localhost:3100",
115-
httpClient: new CustomHttpClient()
116-
)
117-
.CreateLogger();
118-
```
119-
120-
### Sending json content to Loki
121-
Serilog.Sinks.Grafana.Loki can be configured to send json content to Loki, this enables easier filtering in Loki v2, more information about how to filter can be found [here](https://grafana.com/blog/2020/10/28/loki-2.0-released-transform-logs-as-youre-querying-them-and-set-up-alerts-within-loki/)
122-
Example configuration:
123-
```json
124-
{
125-
"Serilog": {
126-
"Using": [
127-
"Serilog.Sinks.Grafana.Loki"
128-
],
129-
"MinimumLevel": {
130-
"Default": "Debug"
131-
},
132-
"WriteTo": [
133-
{
134-
"Name": "GrafanaLoki",
135-
"Args": {
136-
"uri": "http://localhost:3100",
137-
"textFormatter": "Serilog.Sinks.Grafana.Loki.LokiJsonTextFormatter, Serilog.Sinks.Grafana.Loki"
138-
}
139-
}
140-
]
141-
}
142-
}
143-
```
144-
145-
### Inspiration and Credits
146-
- [Serilog.Sinks.Loki](https://github.com/JosephWoodward/Serilog-Sinks-Loki)
147-
- [Serilog.Sinks.Http](https://github.com/FantasticFiasco/serilog-sinks-http)
1+
# Serilog.Sinks.Grafana.Loki
2+
3+
[![Build status](https://github.com/mishamyte/serilog-sinks-grafana-loki/workflows/CI/badge.svg)](https://github.com/mishamyte/serilog-sinks-grafana-loki/actions?query=workflow%3ACI)
4+
[![NuGet Version](https://img.shields.io/nuget/v/Serilog.Sinks.Grafana.Loki)](https://www.nuget.org/packages/Serilog.Sinks.Grafana.Loki)
5+
[![Documentation](https://img.shields.io/badge/docs-wiki-blueviolet.svg)](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki)
6+
7+
## Table of contents
8+
- [What is this sink and Loki?](#what-is-this)
9+
- [Features](#features)
10+
- [Comparison with other Loki sinks](#comparison)
11+
- [Breaking changes](#breaking-changes)
12+
- [Quickstart](#quickstart)
13+
- [Custom HTTP Client](#custom-http-client)
14+
- [Sending json content to Loki](#sending-json-content-to-loki)
15+
- [Inspiration and Credits](#inspiration-and-credits)
16+
17+
## What is this sink and Loki?
18+
19+
The Serilog Grafana Loki sink project is a sink (basically a writer) for the Serilog logging framework. Structured log events are written to sinks and each sink is responsible for writing it to its own backend, database, store etc. This sink delivers the data to Grafana Loki, a horizontally-scalable, highly-available, multi-tenant log aggregation system. It allows you to use Grafana for visualizing your logs.
20+
21+
You can find more information about what Loki is over on [Grafana's website here](https://grafana.com/loki).
22+
23+
## Features:
24+
- Formats and batches log entries to Loki via HTTP (using actual API)
25+
- Global and contextual labels support
26+
- Labels filtration modes
27+
- Integration with Serilog.Settings.Configuration
28+
- Customizable HTTP clients
29+
- HTTP client with gzip compression
30+
- Using fast System.Text.Json library for serialization
31+
- Possibility of sending [json logs](https://grafana.com/blog/2020/10/28/loki-2.0-released-transform-logs-as-youre-querying-them-and-set-up-alerts-within-loki/) to Loki
32+
- No dependencies on another sinks
33+
34+
## Comparison
35+
Features comparison table could be found [here](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki/Comparison-with-another-Loki-sinks)
36+
37+
## Breaking changes
38+
The list of breaking changes could be found [here](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki/Breaking-changes)
39+
40+
## Quickstart
41+
The `Serilog.Sinks.Grafana.Loki` NuGet [package could be found here](https://www.nuget.org/packages/Serilog.Sinks.Grafana.Loki). Alternatively you can install it via one of the following commands below:
42+
43+
NuGet command:
44+
```bash
45+
Install-Package Serilog.Sinks.Grafana.Loki
46+
```
47+
.NET Core CLI:
48+
```bash
49+
dotnet add package Serilog.Sinks.Grafana.Loki
50+
```
51+
52+
In the following example, the sink will send log events to Loki available on `http://localhost:3100`
53+
```csharp
54+
ILogger logger = new LoggerConfiguration()
55+
.WriteTo.GrafanaLoki(
56+
"http://localhost:3100")
57+
.CreateLogger();
58+
59+
logger.Information("The god of the day is {@God}", odin)
60+
```
61+
62+
Used in conjunction with [Serilog.Settings.Configuration](https://github.com/serilog/serilog-settings-configuration) the same sink can be configured in the following way:
63+
64+
```json
65+
{
66+
"Serilog": {
67+
"Using": [
68+
"Serilog.Sinks.Grafana.Loki"
69+
],
70+
"MinimumLevel": {
71+
"Default": "Debug"
72+
},
73+
"WriteTo": [
74+
{
75+
"Name": "GrafanaLoki",
76+
"Args": {
77+
"uri": "http://localhost:3100",
78+
"labels": [
79+
{
80+
"key": "app",
81+
"value": "web_app"
82+
}
83+
],
84+
"outputTemplate": "{Timestamp:dd-MM-yyyy HH:mm:ss} [{Level:u3}] [{ThreadId}] {Message}{NewLine}{Exception}"
85+
}
86+
}
87+
]
88+
}
89+
}
90+
```
91+
92+
Description of parameters and configuration details could be found [here](https://github.com/mishamyte/serilog-sinks-grafana-loki/wiki/Application-settings).
93+
94+
### Custom HTTP Client
95+
Serilog.Loki.Grafana.Loki exposes `ILokiHttpClient` interface with the main operations, required for sending logs.
96+
In order to use a custom HttpClient you can extend of default implementations:
97+
- `Serilog.Sinks.Grafana.Loki.HttpClients.BaseLokiHttpClient` (implements creation of internal `HttpClient` and setting credentials)
98+
- `Serilog.Sinks.Grafana.Loki.HttpClients.LokiHttpClient` (default client which sends logs via HTTP)
99+
- `Serilog.Sinks.Grafana.Loki.HttpClients.LokiGzipHttpClient` (default client which sends logs via HTTP with gzip compression)
100+
101+
or create one implementing `Serilog.Sinks.Grafana.Loki.ILokiHttpClient`.
102+
103+
```csharp
104+
// CustomHttpClient.cs
105+
106+
public class CustomHttpClient : BaseLokiHttpClient
107+
{
108+
public override Task<HttpResponseMessage> PostAsync(string requestUri, Stream contentStream);
109+
{
110+
return base.PostAsync(requestUri, content);
111+
}
112+
}
113+
```
114+
```csharp
115+
// Usage
116+
117+
Log.Logger = new LoggerConfiguration()
118+
.WriteTo.GrafanaLoki(
119+
"http://localhost:3100",
120+
httpClient: new CustomHttpClient()
121+
)
122+
.CreateLogger();
123+
```
124+
125+
### Sending json content to Loki
126+
Serilog.Sinks.Grafana.Loki can be configured to send json content to Loki, this enables easier filtering in Loki v2, more information about how to filter can be found [here](https://grafana.com/blog/2020/10/28/loki-2.0-released-transform-logs-as-youre-querying-them-and-set-up-alerts-within-loki/)
127+
Example configuration:
128+
```json
129+
{
130+
"Serilog": {
131+
"Using": [
132+
"Serilog.Sinks.Grafana.Loki"
133+
],
134+
"MinimumLevel": {
135+
"Default": "Debug"
136+
},
137+
"WriteTo": [
138+
{
139+
"Name": "GrafanaLoki",
140+
"Args": {
141+
"uri": "http://localhost:3100",
142+
"textFormatter": "Serilog.Sinks.Grafana.Loki.LokiJsonTextFormatter, Serilog.Sinks.Grafana.Loki"
143+
}
144+
}
145+
]
146+
}
147+
}
148+
```
149+
150+
### Inspiration and Credits
151+
- [Serilog.Sinks.Loki](https://github.com/JosephWoodward/Serilog-Sinks-Loki)
Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,41 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Threading.Tasks;
5-
using Microsoft.AspNetCore.Builder;
6-
using Microsoft.AspNetCore.Hosting;
7-
using Microsoft.AspNetCore.HttpsPolicy;
8-
using Microsoft.AspNetCore.Mvc;
9-
using Microsoft.Extensions.Configuration;
10-
using Microsoft.Extensions.DependencyInjection;
11-
using Microsoft.Extensions.Hosting;
12-
using Microsoft.Extensions.Logging;
13-
14-
namespace Serilog.Sinks.Grafana.Loki.SampleWebApp
15-
{
16-
public class Startup
17-
{
18-
public Startup(IConfiguration configuration)
19-
{
20-
Configuration = configuration;
21-
}
22-
23-
public IConfiguration Configuration { get; }
24-
25-
// This method gets called by the runtime. Use this method to add services to the container.
26-
public void ConfigureServices(IServiceCollection services)
27-
{
28-
services.AddControllers();
29-
}
30-
31-
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
32-
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
33-
{
34-
if (env.IsDevelopment())
35-
{
36-
app.UseDeveloperExceptionPage();
37-
}
38-
39-
app.UseHttpsRedirection();
40-
41-
app.UseRouting();
42-
43-
app.UseAuthorization();
44-
45-
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
46-
}
47-
}
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.Extensions.Configuration;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Hosting;
6+
7+
namespace Serilog.Sinks.Grafana.Loki.SampleWebApp
8+
{
9+
public class Startup
10+
{
11+
public Startup(IConfiguration configuration)
12+
{
13+
Configuration = configuration;
14+
}
15+
16+
public IConfiguration Configuration { get; }
17+
18+
// This method gets called by the runtime. Use this method to add services to the container.
19+
public void ConfigureServices(IServiceCollection services)
20+
{
21+
services.AddControllers();
22+
}
23+
24+
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
25+
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
26+
{
27+
if (env.IsDevelopment())
28+
{
29+
app.UseDeveloperExceptionPage();
30+
}
31+
32+
app.UseHttpsRedirection();
33+
34+
app.UseRouting();
35+
36+
app.UseAuthorization();
37+
38+
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
39+
}
40+
}
4841
}

0 commit comments

Comments
 (0)