datalust / nlog-targets-seq Goto Github PK
View Code? Open in Web Editor NEWAn NLog target that writes events to Seq. Built for NLog 4.5+.
Home Page: https://getseq.net
License: Apache License 2.0
An NLog target that writes events to Seq. Built for NLog 4.5+.
Home Page: https://getseq.net
License: Apache License 2.0
{
"@t": "2018-04-06T10:52:17.2967668Z",
"@mt": "Removed sequence entry for Job: {Job.Id} as it completed with the state: {Job.State}.",
"@m": "Removed sequence entry for Job: {Job.Id} as it completed with the state: {Job.State}.",
"@i": "5f2536b7",
"@l": "Debug",
"MachineName": "XXX",
"SiteName": "XXX",
"Logged": "2018/04/06 12:52:17.296",
"Level": "Debug",
"Solution": "XXX",
"Message": "Removed sequence entry for Job: \"223234\" as it completed with the state: \"Deleted\".",
"Logger": "CleanupSequenceJobFilterAttribute",
"Properties": "Job.Id=223234|Job.State=Deleted",
"Https": "false",
"RemoteAddress": ": - ",
"Callsite": "CleanupSequenceJobFilterAttribute.OnStateApplied",
"Job.Id": "223234",
"Job.State": "Deleted"
}
Shouldn't @m
be the value in the Message
and not the MessageTemplate aka @mt
? Dont know if this is a log target issue or a configuration issue either in seq or with nlog?
Hello,
This example https://github.com/304NotModified/NLog-Demo-cases/tree/master/AspNetCore2WithConfigSetting
works fine unitl I try to add a Seq target with a ${configsetting}
To reproduce:
Target.Register<SeqTarget>("Seq");
as first line in Program.cs<target xsi:type="Seq" name="ownFile-web" serverUrl="${configsetting:name=serverUrl}">
<property name="Source" value="Seq Target Test"/>
</target>
"serverUrl": "http://webtest4:5341/"
to appsettings.json<PackageReference Include="NLog.Targets.Seq" Version="1.2.0-dev-00075" />
to csprojinternal log:
Error Seq Target[ownFile-web]: Error initializing target Exception: System.UriFormatException: Invalid URI: The format of the URI could not be determined.
Am I doing something wrong?
There is an option to configure NLog from appsettings.json instead of NLog.config, so I guess it will be really usefull to provide some example in README on how to configure properly Seq target with properties.
We are sending events to our seq server by using an API key.
When using minimum level (API key configuration page on SEQ) Info no Info level events are accepted on the seq server. Error and fatal level events will get through. Same for Debug or Verbose. Only accepting all events (setting minimum level to blank) will result in getting Info level / debug level events as well.
I assume that at some point the target is setting the event level not according to what seq expects, maybe?
Hi,
I am testing on vs2015 on a simple project and it works but if i update NLog
NLog 4.5.0-alpha2 -> NLog 4.5.0-alpha3
or NLog 4.5.0-alpha2 -> NLog 5.0.0-beta5
nothing is logged in seq. Code:
logger.Info("Hello, {Server}, from {Library}", server, library);
// Text logging: the two properties are captured using positional arguments:
logger.Info("Goodbye, {0}, from {1}", server, library);
The new "compact" JSON format is used in this sink.
I think the test cases here could be ported directly: https://github.com/serilog/serilog-formatting-compact/blob/dev/test/Serilog.Formatting.Compact.Tests/CompactJsonFormatterTests.cs.
(We might move over to the more efficient Layout
mechanism in the process...? See #1.)
IWebProxy proxy = WebRequest.GetSystemWebProxy();
proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
request.Proxy = proxy;
request.PreAuthenticate = true;
Cache the default proxy to avoid auto lookup for every WebRequest.
Maybe a tristate (Explicit Proxy, Auto Proxy, Without Proxy - null):
https://stackoverflow.com/questions/2519655/httpwebrequest-is-extremely-slow
Can also be configured globally for the entire application:
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true">
<proxy usesystemdefault="True" />
</defaultProxy>
</system.net>
There are paragraph about how to add custom properties, but I can't remove default ones. E.g. I want to remove ActionName from AspNetCore request (it's added automatically), and I can't. I tried it with
<propertyFilter> <remove regexToMatch="ActionName" /> </propertyFilter>
or excludeProperties="ActionName"
in target, or overriding as <property name="ActionName" value="something" />
, but it's got overriden and initial ActionName stays in log
More detailed config:
<target name="seq" xsi:type="BufferingWrapper" bufferSize="1000" flushTimeout="2000" > <target xsi:type="Seq" serverUrl="http://localhost:5341" apiKey="" excludeProperties="ActionName" > <propertyFilter> <remove regexToMatch="ActionName" /> </propertyFilter> <property name="MachineName" value="${machinename}" /> <property name="ActionName" value="something" /> </target> </target>
I just tried the examples here without explicitly fiddling with layout.
https://github.com/nlog/nlog/wiki/How-to-use-structured-logging
They all log as expected to file but for Seq the collection examples just output type names, e.g., Test System.String[] instead of Test "a", "b."
logger.Info("Test {value1}", new List<string> { "a", "b" }); // list of strings. Result: Test "a", "b"
logger.Info("Test {value1}", new[] { "a", "b" }); // array. Result: Test "a", "b"
logger.Info("Test {value1}", new Dictionary<string, int> { { "key1", 1 }, { "key2", 2 } }); // dict. Result: Test "key1"=1, "key2"=2
I notice that Seq.Client.NLog is Oct 9th, so is that an issue?
I'm trying to use ILogger.BeginScope
to record structured object data, and have it recorded in Seq
in JSON format so it can be queried, but it's consistently showing up as just strings, which is doesn't allow me to query it. I posted some of the issue here stackoverflow, and also tried one of the viable suggestions, but it doesn't work either.
I'm not sure if this is an issue in NLog or NLog.Targets.Seq.
I made an example web api controller in my .net 6 c# app for testing this, and the output in Seq
is below after running it.
In the following test, only the first row (ObjectsOp2
) generates the desired JSON format in Seq
that is actually searchable as structured data.
I tried one of the viable stackoverflow suggestions of using a scope level layout ${scopenested:format=@}
, but that produces JSON in string format rather than raw JSON in Seq
, so it's not searchable or a workable solution. It gets output in each log as the Scope
property.
Is there a bug in NLog.Targets.Seq specifically for the layout ${scopenested:format=@}
? Seems like that should work.
NlogController
[ApiController]
[Route("[controller]")]
public class NlogController : Controller
{
private readonly ILogger<NlogController> _logger;
public NlogController(ILogger<NlogController> logger)
{
_logger = logger;
}
public class Test1Class
{
public class Test1InnerClass
{
public string Name { get; set; } = "";
public string Description { get; set; } = "";
}
public int Id { get; set; }
public List<Test1InnerClass> Tags { get; set; } = new List<Test1InnerClass>();
}
[HttpPost(nameof(Test1))]
public Task Test1()
{
var objects = new Test1Class
{
Id = 1,
Tags =
{
new Test1Class.Test1InnerClass
{
Name = "global",
Description = "global tag"
},
new Test1Class.Test1InnerClass
{
Name = "exactMatch",
Description = "exactMatch tag"
}
}
};
using (_logger.BeginScope(new Dictionary<string, object>
{
["OrderId"] = 3456,
["ObjectsScope1"] = objects,
["@ObjectsScope2"] = objects,
["{@ObjectsScope3}"] = objects
}))
{
_logger.LogInformation("String message with no additional parameters tied to it.");
_logger.LogInformation("String message with a parameter tied to it using format: {{ObjectsOp1}}. {ObjectsOp1}", objects);
_logger.LogInformation("String message with a parameter tied to it using format: {{@ObjectsOp2}}. {@ObjectsOp2}", objects);
}
return Task.CompletedTask;
}
}
appsettings.json
"NLog": {
"autoReload": true,
"throwConfigExceptions": true,
"internalLogLevel": "Info",
"internalLogFile": "${basedir}/internal-nlog.txt",
"extensions": [
{ "assembly": "NLog.Extensions.Logging" },
{ "assembly": "NLog.Web.AspNetCore" },
{ "assembly": "Microsoft.Data.SqlClient" },
{ "assembly": "NLog.Targets.Seq" }
],
"default-wrapper": {
"type": "AsyncWrapper",
"overflowAction": "Block"
},
"targets": {
"async": true,
"logconsole": {
"type": "Console"
},
"seq": {
"type": "BufferingWrapper",
"bufferSize": 200,
"flushTimeout": 2000,
"slidingTimeout": false,
"target": {
"type": "Seq",
"serverUrl": "http://localhost:4005",
"apiKey": "",
"properties": [
{
"name": "Level",
"value": "${level}"
},
{
"name": "Scope",
"value": "${scopenested:format=@}"
},
{
"name": "CacheValueTest",
"value": "${scopeproperty:CacheValue:format=@}"
},
{
"name": "MachineName",
"value": "${machinename}"
},
{
"name": "Logger",
"value": "${logger}"
},
{
"name": "Callsite",
"value": "${callsite}"
},
{
"name": "Exception",
"value": "${exception:tostring}"
},
{
"name": "TraceId",
"value": "${aspnet-TraceIdentifier}"
},
{
"name": "Url",
"value": "${aspnet-request-url}${aspnet-request-querystring}"
},
{
"name": "Referer",
"value": "${aspnet-request-referrer}"
},
{
"name": "RequestMethod",
"value": "${aspnet-request-method}"
},
{
"name": "UserAgent",
"value": "${aspnet-request-useragent}"
},
{
"name": "ClientIpAddress",
"value": "${aspnet-request-ip:CheckForwardedForHeader=true}"
}
]
}
},
"rules": [
{
"logger": "*",
"minLevel": "Debug",
"writeTo": "logconsole"
},
{
"logger": "Ripple.*",
"minLevel": "Debug",
"writeTo": "seq"
},
{
"logger": "Microsoft.*",
"minLevel": "Off",
"final": true
}
]
row 1
{
"@t": "2022-05-31T21:11:07.7751772Z",
"@mt": "String message with a parameter tied to it using format: {{@ObjectsOp2}}. {@ObjectsOp2}",
"@m": "String message with a parameter tied to it using format: {@ObjectsOp2}. {\n \"Id\": 1,\n \"Tags\": [\n {\n \"Name\": \"global\",\n \"Description\": \"global tag\"\n },\n {\n \"Name\": \"exactMatch\",\n \"Description\": \"exactMatch tag\"\n }\n ]\n}",
"@i": "11088dc7",
"Level": "Info",
"Scope": "[ { \"ConnectionId\": \"0HMI3987KKG0L\" }, { \"RequestId\": \"0HMI3987KKG0L:00000009\", \"RequestPath\": \"/Nlog/Test1\" }, { \"ActionId\": \"bd4fb72b-ea24-43d6-8960-5211ec8dbaae\", \"ActionName\": \"Ripple.Rest.Controllers.NlogController.Test1 (Ripple.Rest)\" }, { \"UserName\": \"Unknown User\", \"UserId\": 0 }, { \"OrderId\": 3456, \"ObjectsScope1\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]}, \"@ObjectsScope2\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]}, \"{@ObjectsScope3}\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]} } ]",
"CacheValueTest": "null",
"MachineName": "DESKTOP-QVMC0TS",
"Logger": "Ripple.Rest.Controllers.NlogController",
"Callsite": "Ripple.Rest.Controllers.NlogController.Test1",
"TraceId": "00-8c95b52c3ee70d8cadd18547a13d9816-56e4d8037b71839f-00",
"Url": "https://localhost/Nlog/Test1",
"Referer": "https://localhost:7165/swagger/index.html",
"RequestMethod": "POST",
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
"ClientIpAddress": "::1",
"ConnectionId": "0HMI3987KKG0L",
"RequestId": "0HMI3987KKG0L:00000009",
"RequestPath": "/Nlog/Test1",
"ActionId": "bd4fb72b-ea24-43d6-8960-5211ec8dbaae",
"ActionName": "Ripple.Rest.Controllers.NlogController.Test1 (Ripple.Rest)",
"UserName": "Unknown User",
"UserId": 0,
"OrderId": 3456,
"ObjectsScope1": "Ripple.Rest.Controllers.NlogController+Test1Class",
"@@ObjectsScope2": "Ripple.Rest.Controllers.NlogController+Test1Class",
"{@ObjectsScope3}": "Ripple.Rest.Controllers.NlogController+Test1Class",
"ObjectsOp2": {
"Id": 1,
"Tags": [
{
"Name": "global",
"Description": "global tag"
},
{
"Name": "exactMatch",
"Description": "exactMatch tag"
}
]
}
}
row 2
{
"@t": "2022-05-31T21:11:07.7717526Z",
"@mt": "String message with a parameter tied to it using format: {{ObjectsOp1}}. {ObjectsOp1}",
"@m": "String message with a parameter tied to it using format: {ObjectsOp1}. Ripple.Rest.Controllers.NlogController+Test1Class",
"@i": "a4227fe6",
"Level": "Info",
"Scope": "[ { \"ConnectionId\": \"0HMI3987KKG0L\" }, { \"RequestId\": \"0HMI3987KKG0L:00000009\", \"RequestPath\": \"/Nlog/Test1\" }, { \"ActionId\": \"bd4fb72b-ea24-43d6-8960-5211ec8dbaae\", \"ActionName\": \"Ripple.Rest.Controllers.NlogController.Test1 (Ripple.Rest)\" }, { \"UserName\": \"Unknown User\", \"UserId\": 0 }, { \"OrderId\": 3456, \"ObjectsScope1\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]}, \"@ObjectsScope2\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]}, \"{@ObjectsScope3}\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]} } ]",
"CacheValueTest": "null",
"MachineName": "DESKTOP-QVMC0TS",
"Logger": "Ripple.Rest.Controllers.NlogController",
"Callsite": "Ripple.Rest.Controllers.NlogController.Test1",
"TraceId": "00-8c95b52c3ee70d8cadd18547a13d9816-56e4d8037b71839f-00",
"Url": "https://localhost/Nlog/Test1",
"Referer": "https://localhost:7165/swagger/index.html",
"RequestMethod": "POST",
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
"ClientIpAddress": "::1",
"ConnectionId": "0HMI3987KKG0L",
"RequestId": "0HMI3987KKG0L:00000009",
"RequestPath": "/Nlog/Test1",
"ActionId": "bd4fb72b-ea24-43d6-8960-5211ec8dbaae",
"ActionName": "Ripple.Rest.Controllers.NlogController.Test1 (Ripple.Rest)",
"UserName": "Unknown User",
"UserId": 0,
"OrderId": 3456,
"ObjectsScope1": "Ripple.Rest.Controllers.NlogController+Test1Class",
"@@ObjectsScope2": "Ripple.Rest.Controllers.NlogController+Test1Class",
"{@ObjectsScope3}": "Ripple.Rest.Controllers.NlogController+Test1Class",
"ObjectsOp1": "Ripple.Rest.Controllers.NlogController+Test1Class"
}
row 3
{
"@t": "2022-05-31T21:11:07.7717526Z",
"@mt": "String message with a parameter tied to it using format: {{ObjectsOp1}}. {ObjectsOp1}",
"@m": "String message with a parameter tied to it using format: {ObjectsOp1}. Ripple.Rest.Controllers.NlogController+Test1Class",
"@i": "a4227fe6",
"Level": "Info",
"Scope": "[ { \"ConnectionId\": \"0HMI3987KKG0L\" }, { \"RequestId\": \"0HMI3987KKG0L:00000009\", \"RequestPath\": \"/Nlog/Test1\" }, { \"ActionId\": \"bd4fb72b-ea24-43d6-8960-5211ec8dbaae\", \"ActionName\": \"Ripple.Rest.Controllers.NlogController.Test1 (Ripple.Rest)\" }, { \"UserName\": \"Unknown User\", \"UserId\": 0 }, { \"OrderId\": 3456, \"ObjectsScope1\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]}, \"@ObjectsScope2\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]}, \"{@ObjectsScope3}\": {\"Id\":1, \"Tags\":[{\"Name\":\"global\", \"Description\":\"global tag\"},{\"Name\":\"exactMatch\", \"Description\":\"exactMatch tag\"}]} } ]",
"CacheValueTest": "null",
"MachineName": "DESKTOP-QVMC0TS",
"Logger": "Ripple.Rest.Controllers.NlogController",
"Callsite": "Ripple.Rest.Controllers.NlogController.Test1",
"TraceId": "00-8c95b52c3ee70d8cadd18547a13d9816-56e4d8037b71839f-00",
"Url": "https://localhost/Nlog/Test1",
"Referer": "https://localhost:7165/swagger/index.html",
"RequestMethod": "POST",
"UserAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
"ClientIpAddress": "::1",
"ConnectionId": "0HMI3987KKG0L",
"RequestId": "0HMI3987KKG0L:00000009",
"RequestPath": "/Nlog/Test1",
"ActionId": "bd4fb72b-ea24-43d6-8960-5211ec8dbaae",
"ActionName": "Ripple.Rest.Controllers.NlogController.Test1 (Ripple.Rest)",
"UserName": "Unknown User",
"UserId": 0,
"OrderId": 3456,
"ObjectsScope1": "Ripple.Rest.Controllers.NlogController+Test1Class",
"@@ObjectsScope2": "Ripple.Rest.Controllers.NlogController+Test1Class",
"{@ObjectsScope3}": "Ripple.Rest.Controllers.NlogController+Test1Class",
"ObjectsOp1": "Ripple.Rest.Controllers.NlogController+Test1Class"
}
After upgrading NLog to 5.0.0 and NLog.Extensions.Logging to 5.0.0 the Seq target does not work anymore. I get an exception on:
NLogConfigurationException: Failed to create Target of type: Seq
NLog.Config.LoggingConfigurationParser.FactoryCreateInstance(string classType, INamedItemFactory<T, Type> factory)
I am using the default appsettings.json configuration as shown in the documentation for this package.
I did see in the breaking changes for NLog 5.0.0 that they changes some properties (such as bufferSize
and flushTimeout
from int to Layout in this commit part of changes to the BufferWrapper feature also used by this packages, see PR/Commit: https://github.com/NLog/NLog/pull/4858/files
The NLog 4.7.14 and NLog.Extensions.Logging 1.7.4 I was using in combination with NLog.Targets.Seq 2.1.0 does work. This prevents upgrading to NLog 5.0.0
Right now, when using properties as described in the readme.md you can use layout renderers as long as they're available by adding them as an extension (I believe). I'm however using the LayoutRenderer.Register lambda, which fails the initialization of the Seq target if I use that layout renderer because it hasn't been registered yet when NLog initializes itself and the target.
Could a solution be allowing adding properties to the SeqTarget Properties member? Right now that's not possible because of the private setter. Any other ideas?
I have an Seq target like so:
<targets>
<target name="seq" xsi:type="BufferingWrapper" bufferSize="1000" flushTimeout="2000">
<target xsi:type="Seq" serverUrl="https://ourServer" apiKey="asd" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="seq" />
</rules>
<extensions>
<add assembly="NLog.Targets.Seq" />
</extensions>
And I can push some additional scope properties:
logger.PushScopeProperty("ArrayTest", New Integer() {1, 2, 3})
logger.PushScopeProperty("DictTest", New Dictionary(Of String, Object) From {{"KeyWithArray", New Integer() {1, 2, 3}}, {"KeyWithString", "Hello"}})
Now, in the case of ArrayTest
and ArrayInDictTest
, Seq recognizes these as JSON. However, in the latter case, the array inside the dictionary is treated as empty:
ArrayTest
[1, 2, 3]
DictTest
{
KeyWithArray: [],
KeyWithString: 'Hello'
}
Both keys are there, but only the string gets a value.
This is with target versions 2.1.0 and 3.0.0 on .NET 4.7.2, and Seq version 2023.4.10146.
(I'm not a 100% that this is on the target's end. However, I believe it works with the equivalent Serilog NuGet package.)
could not work with nlog5.0x
it is good with nlog4.7.15
version:
NLog.Targets.Seq V2.10
net4.72 / net6.0
Seq 2021.4
Hello, is it possible to substitute serverUrl value in NLog.config from appsettings like this?
<nlog>
<targets>
<target name="seq" type="Seq" serverUrl="${appsetting:name=SeqEndpointUrl}" apiKey="some api key">
</targets>
</nlog>
I've also tried to make nlog variable, it does not work as well ;/
However, <property value/>
substitutoin works somehow:
<target name="seq" type="Seq" serverUrl="http://ihavetohardcodethis.com" apiKey="some api key">
<property name="Source" value="${appsetting:name=Works}" />
</target>
See #17 (comment)
@nblumhardt I guess NLog has come out of alpha stage, and the documentation can be updated too:
For events to be valid "compact JSON", the @r
renderings property array must have exactly one element per formatted message template token.
In RenderingsTarget
, the rendering isn't included in the array if the capture type is other than Normal
, if there are no properties on the event, or if the property is missing: https://github.com/datalust/nlog-targets-seq/blob/dev/src/NLog.Targets.Seq/RenderingsLayout.cs#L55
This means an event like:
Logger.Info("Hello {@Broken:000}", 5);
produces "@r":[]
when instead it should either include a placeholder value, or be omitted entirely.
So that the message template can be accurately rendered on the remote machine, any formatted tokens in the message template need to be pre-rendered.
E.g.:
logger.Info("The number is {N:000.00}", 42);
Here we want to retrieve the format 000.00
associated with the N
property.
@304NotModified any clue how this can be achieved?
Here, we want to check if a positional template is being used so that the Parameters
collection can be included:
@304NotModified any suggestions here? It seems like it's basically the same API requirement as #2 - get access to the parsed message template.
I imagine this might be as simple as just re-parsing the template in the target when required.
When serializing to a file it is possible to serialize all properties with layout render like this:
<layout xsi:type="JsonLayout" includeAllProperties="true" maxRecursionLimit="20" excludeProperties="...." >
It is not possible to add includeAllProperties, maxRecursionLimit and excludeProperties to seq target.
Background for this request:
I am trying to log properties using nlog-targests-seq so they are searchable.
I know I can use @ to serialize objects in messages - but is seems not possible for user properties?
Pseudo c# code that works (I can e.g. search for x.status=0 i seq):
class MyClass { public int status { get; set; } };
var x = new MyClass();
log.Debug().Message("Write {@x}", x).Write();
Pseudo c# code not working (only x class name is serialized so I can not search for x.status=0):
class MyClass { public int status { get; set; }
var x= new MyClass();
log.Debug().Message("Write Hi").Property("x", x).Write();
Today I have to format every property into the message string - this does not seem like an optimal method for structured logging.
I am very happy to see the structured efforts of NLog 4.5 finally coming to fruition and a "real" Seq target! ๐ โค๏ธ
Because this target sends logs over the network, it is important that:
For the last bullet, it is important that messages be human-readable (not necessarily "nice", their json payload would be acceptable).
Lack of this feature would mean having a second file target beside the seq target. It would absolutely work but it would be a waste of resources since a lot of work would be duplicated for no reason.
Hi,
I asked this question on SO, and thought I should repeat it here:
https://stackoverflow.com/questions/76665941/nlog-targets-seq-and-composite-formatting
Any advice would be appreciated.
I am using NLog and currently using a custom layout renderer to convert all properties to json to file based on following SO answer.
setup works properly for File target where json gets serialized
and I have following setup for NLog.Targets.Seq
<target name="seq" xsi:type="Seq" serverUrl="http://localhost:5341">
<property name ='properties' value='${json-event-properties}'/>
</target>
this gets sent as string instead of a json object to seq.
I verified it by downloading Raw Json from Seq.
I think adding an attribute to let Nlog.Targets.Seq know that passed string is json and making necessary changes in the nuget will help resolve the issue.
e.g.
<target name="seq" xsi:type="Seq" serverUrl="http://localhost:5341">
<property name ='properties' value='${json-event-properties}' isJson=true/>
</target>
The following should log structured data:
logger.Info("Hello, {@User}", new User { Name = "Alice" });
While the example without @
should log using ToString()
:
logger.Info("Hello, {User}", new User { Name = "Alice" });
At present, both will use ToString
, although in both cases the value of the A
property will be the User
object.
Similar to Serilog.Sinks.Seq
, add a feature so NLog may also only send logs that are the minimum level and above, as per response body from the Seq server with each batch of events sent.
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.