serilog-contrib / serilog-sinks-slack Goto Github PK
View Code? Open in Web Editor NEWA simple (yet customizable) Slack logging sink for Serilog
License: MIT License
A simple (yet customizable) Slack logging sink for Serilog
License: MIT License
I haven't really dug into the problem yet but the symptoms first showed when a service wouldn't start up. Running the exe interactively resulted in:
Stack overflow.
Repeat 8733 times:
--------------------------------
at Serilog.Sinks.PeriodicBatching.PeriodicBatchingSink.Dispose()
at Serilog.Sinks.Slack.SlackSink.Dispose(Boolean)
at Serilog.Sinks.Slack.SlackSink.Dispose()
--------------------------------
at Serilog.LoggerConfiguration+<>c__DisplayClass33_0.<CreateLogger>g__Dispose|1()
at Serilog.Extensions.Hosting.ReloadableLogger.Reload(System.Func`2<Serilog.LoggerConfiguration,Serilog.LoggerConfiguration>)
at Serilog.SerilogServiceCollectionExtensions+<>c__DisplayClass3_0.<AddSerilog>b__0(System.IServiceProvider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier)
at System.Collections.Concurrent.ConcurrentDictionary`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].GetOrAdd(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, System.Func`2<Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier,System.__Canon>)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(System.Type)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(System.IServiceProvider, System.Type)
at Serilog.SerilogServiceCollectionExtensions+<>c__DisplayClass3_0.<AddSerilog>b__2(System.IServiceProvider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(Microsoft.Extensions.DependencyInjection.ServiceLookup.ConstructorCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(Microsoft.Extensions.DependencyInjection.ServiceLookup.ConstructorCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier)
at System.Collections.Concurrent.ConcurrentDictionary`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].GetOrAdd(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, System.Func`2<Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier,System.__Canon>)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(System.Type)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(System.IServiceProvider, System.Type)
at Microsoft.Extensions.Hosting.HostBuilder+<>c__DisplayClass35_0.<PopulateServiceCollection>b__2(System.IServiceProvider)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier)
at System.Collections.Concurrent.ConcurrentDictionary`2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].GetOrAdd(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, System.Func`2<Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier,System.__Canon>)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceIdentifier, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(System.Type)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(System.IServiceProvider, System.Type)
at Microsoft.Extensions.Hosting.HostBuilder.ResolveHost(System.IServiceProvider, System.Diagnostics.DiagnosticListener)
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at System.Linq.Utilities+<>c__DisplayClass2_0`3[[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<CombineSelectors>b__0(System.__Canon)
at System.Linq.Enumerable+SelectArrayIterator`2[[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.__Canon, System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
at System.Threading.Tasks.Task.WhenAll(System.Collections.Generic.IEnumerable`1<System.Threading.Tasks.Task>)
at ServiceBase.ServiceHost+<RunBackgroundServices>d__1.MoveNext()
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[ServiceBase.ServiceHost+<RunBackgroundServices>d__1, ServiceBase, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]](<RunBackgroundServices>d__1 ByRef)
at ServiceBase.ServiceHost.RunBackgroundServices(System.Collections.Generic.IEnumerable`1<System.Action`2<Microsoft.Extensions.Hosting.HostBuilderContext,Microsoft.Extensions.DependencyInjection.IServiceCollection>>)
at Program+<<Main>$>d__0.MoveNext()
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Program+<<Main>$>d__0, ItemWorker, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]](<<Main>$>d__0 ByRef)
at Program.<Main>$(System.String[])
at Program.<Main>(System.String[])
today, only the Level and the Timestamp are hard coded sent to slack.
what if my log message look like this:
_logger.LogInformation("{ClientIp} has Joined", IP);
i would expect to have another field ClientIp (the same as ElasticSerach Sink does).
any chance to have this in the next drop?
The Serilog.Sinks.Slack
NuGet package doesn't yet have an icon.
I suggest using the standard icon for sinks:
More details: https://github.com/serilog-contrib/brand
I tried using the sink using https://github.com/serilog/serilog-settings-configuration but it didn't work:
"Serilog": {
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Information",
"System": "Information"
}
},
"WriteTo": [
{
"Name": "Slack",
"Args": {
"WebHookUrl": "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
}
]
}
When building a strong-named assembly referencing this sink, one will get the warning below during the build.
CSC : warning CS8002: Referenced assembly 'Serilog.Sinks.Slack, Version=1.2.56.0, Culture=neutral, PublicKeyToken=null' does not have a strong name.
Signing the assembly with a strong name is a best practice, and would cause no side-effects whatsoever to anyone.
I've started using this project and I've noticed that alerts are not slacked before my console application exit.
I'm not sure if this is a bug? Or is this the expected behavior?
For now, I've added a thread sleep before exit but I'd like to know if it's a bug and if not how people using this library usually account for this...?
I've been using another slack sink (ServiceStack.Logging.Slack) and all slack alerts are slacked properly before the application exit without adding a thread sleep.
But I need to use ServiceStack.Logging.Serilog and if I want to use Slack I need to use serilog-sinks-slack with it.
It seems it's possible to do this without adding a Thread sleep since it works with the default ServiceStack.Logging.Slack.
Thanks for any pointers ;-)
Currently, the timestamp attachment is not formatted and is just written as DateTimeOffset.ToString()
, which is depending on the culture of the current thread.
https://github.com/mgibas/serilog-sinks-slack/blob/master/Serilog.Sinks.Slack/SlackSink.cs#L89
new Field{Title = "Timestamp", Value = logEvent.Timestamp.ToString(), Short = _options.DefaultAttachmentsShortFormat}
Would it be possible to add support for custom timestamp attachment formats, so you can use any format you like, without having to rely on the current machine culture?
I would like to use this project but I need to know under which license I can use it.
First of all thank you for the great sink.
I've used it and noticed that if the the stack trace of an exception is too long, the message gets cut and the formatting gets lost: the texts starts with ``` but the matching end markdown is never reached (I see ...). Would it be possible to limit the message correctly in order to display the stack trace correctly formatted? It may even be interesting to have a max char configuration for this (since I don't know if this is configurable in Slack).
It would be good if each log level (info, debug, trace, warning, error, critical, etc) could have their own channel specified to send messages to.
I have two Slack Sinks that log to different Channels.
One Channel is for logs and the other is for alerts. Like below:
.WriteTo.Slack(
webhookUrl: "https://hooks.slack.com/services/hook1",
//hook for alerting CST
customChannel: "aletr",
customUsername: $"alert-bot",
customIcon: ":radioactive_sign:",
restrictedToMinimumLevel: LogEventLevel.Fatal
)
.WriteTo.Slack(
webhookUrl: "https://hooks.slack.com/services/hook2",
customChannel: "logs",
customUsername: $"log-bot",
customIcon: ":radioactive_sign:",
restrictedToMinimumLevel: LogEventLevel.Error
);
Currently I am managing this by making the alert Channels log level as Fatal. But I wan to log Certain Errors as Alerts.
But I cant do that directly as then I will have decrease the logLevel for Alert Channel and it will be polluted by all the Error Logs
When I set my logger up to sink to a webhook, it works when I test it inside visual studio.
The moment I build it however and run the executable, the webhook gets no messages whatsoever.
I've tried both Debug and Release mode, none seem to work.
[edit]: when running the build in .net 4.6.1 it doesn't work, however it works with .net core 1.1
I have used your sink in my application and it was working fine, it has now stopped working at all, I get no exception and nothing strange in Output (visual Studio).
I then tried your example application with my Webhook and that isn't working either, I have tested my Slack Webhook in Command Prompt and it is working fine.
Is anyone else seeing this?
The current implementation uses Serilog's PeriodicBatchingSink. It is set up to receive a message batch, loop the collection, sending each message as a separate HTTP request (a Slack limitation, the API only allows one message).
This isn't a good use case for PeriodicBatchingSink, because if we have a batch of 10 messages, and HTTP request 9 out of 10 is throttled by Slack and fails, the batching sink will retry the entire batch. This will duplicate messages 1 - 8 until all requests for the batch succeed.
What the sink really needs to do is post one at a time, in a way Serilog can retry. Needs some investigation - maybe we can just set the batch size to 1?
I have implemented this in our web app project. I want to log Post Api body details in the error to have details about the API call. But right now there are only some fixed parameters that are auto-generated.
Does this issue relate to a new feature or an existing bug?
Bug
What version of Serilog.Sinks.Elasticsearch is affected?
2.0.3
What is the target framework and operating system?
Net Core 3.1
Please describe the current behavior?
When using minimumLogEventLevel via json based configuration the set value is neither checked nor used. All events are being sent.
a minimal demo of the problem
create empty project
install Serilog
install Serilog.Sinks.Slak
configure something like this:
{
"Name": "Slack",
"Args": {
"WebHookUrl": "https://hooks.slack.com/services/XXXXX",
"CustomChannel": "#errors",
"CustomUserName": "User",
"MinimumLogEventLevel": "Warning",
"BatchSizeLimit": 1,
"ShowExceptionAttachments": true
}
you will find all logs in the channel
Hi guys, thanks for merging my last pull request! The new version wasn't published to NuGet, unfortunately, due to this error.
๐ญ error: Response status code does not indicate success: 403
(The specified API key is invalid, has expired, or does not have permission to access the specified package.).
Would you please check it? You can see the full log here:
https://github.com/serilog-contrib/serilog-sinks-slack/runs/5202446259?check_suite_focus=true
Thanks!
Moreno
Based on a reproducible report by @GFoley83 in issue #23 . The following code should work (and does on .NET Core) but does not when targetting .NET Framework 4.5.2
var config = new LoggerConfiguration().WriteTo.Slack("https://hooks.slack.com/services/XXX");
Log.Logger = config.CreateLogger();
Log.Logger.Information("Hello world");
Log.CloseAndFlush();
Hi,
we recently introduced Slack in our company and I would love to output Error/Fatal log messages into a channel. I managed to do so with this sink in minutes. ๐
While fiddling around with it I tried to set an outputeTemplate
parameter to control the rendered text messages in the logs, but couldn't find any such parameter. Does this sink not support this?
I want to have several web services log into a single channel and without contextual information like the SourceContext
or a RequestID
in the log message it would be impossible to tell from which web service a log came or what's related.
Could you add this parameter to support the typical way of formatting the log messages in Serilog?
Kind regards
Michael
I was wondering why you're using NETStandard.Library for v.4.6 ?
I don't seem to be able to update the package for a solution ASP.NET MVC 4.6.
I'm fine with Slack receiveing at most one error every half an hour and I don't want all the other errors to buildup in the queue and consume application memory.
Please expose the QueueLimit property from the PeriodicBatchingSinkOptions in your SlackSinkOptions.
Thanks!
I have a console app that executes quite quickly and the number of messages is inconsistently relayed to Slack. (i.e out of 6 log messages, sometimes I might see 1 or 2 or 3 but never the full 6.
I understand the limitations of posting to a webhook but I thought that as long as I am disposing correctly that the sink would be fully flushed? Maybe a synchronous option if people really want this enforced?
Thoughts?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.