damianh / liblog Goto Github PK
View Code? Open in Web Editor NEWLibLog is a single file for you to either copy/paste or install via nuget, into your library/framework/application to provide a logging abstraction.
License: MIT License
LibLog is a single file for you to either copy/paste or install via nuget, into your library/framework/application to provide a logging abstraction.
License: MIT License
When a lib that uses LibLog internally is hosted in an exe that uses Fody Costura to embed references (vs finding them on disk), the auto wireup doesn't occur.
When logging using Log4Net when outputting the method name where the logger is used the method name is CallSite.Target rather than the actual method name used.
For example using a Log4Net layout like the following results in incorrect behaviour.
<layout type="log4net.Layout.PatternLayout">
<!-- 	 == TAB character as a seperator between each field.-->
<param name="ConversionPattern" value="[${COMPUTERNAME}]	[%date{ISO8601}]	[%-5level]	[%thread]	[%logger]	[%method]	[%property{NDC}]	[%message %exception] 	%newline" />
</layout>
This outputs the following, CallSite.Target should contain the method name.
[NL-DEV] [2015-01-22 16:29:20,242] [DEBUG] [6] [zhapi.Bootstrapper] [CallSite.Target] [(null)] [Enabling CORS Support ]
See scriptcs/scriptcs#1009 (comment)
As I began to mention last night, the way we're using LibLog in scriptcs is rather unusual, resulting in us providing ILog
extension methods. Anyway, one of those methods is a direct equivalent of LogProvider.GetCurrentClassLogger()
.
Due to the conclusions that the JIT compiler arrives at, the extension method happens to get inlined which alters the stack and caused the StackFrame
stuff to blow up with an NRE. The cause of the issue was very hard to determine because the stack trace was very misleading. I just happened to notice that we were only getting the failure in Release and not Debug, so I took a punt on that method, shoved [MethodImpl(MethodImplOptions.NoInlining)]
onto it, and hey presto, it fixed the problem.
Anyway, I'm not sure if anyone's run into this with LibLog. I guess not, and that's probably just a lucky outcome of the JIT, but I wonder if it may be worth putting the attribute on that method now to insulate it against a different JIT heuristic in the future. After all, .NET 4.6 is getting a new 64-bit JIT and who knows what that might do, in it's final form, against this method? I suppose if you're ever playing with StackFrame
in a method like this it's probably a very good idea to deterministically prevent inlining to keep the method behaving as you want it to.
Hi,
Nice project!
I have a question - I want to set some GlobalContext/ThreadContext variables in case the user uses log4net. I can't see any method which supports this. Castle's logging interface seem to support this using an interface named IExtendedLogger which has a property that allows access to these contexts.
Are there any plans to add support for this to LibLog? will you accept a pull request for this kind of feature?
Thanks
Hi
I am attempting to use LibLog with new preview of VS 2015.
I 'dropped' LibLog.cs into new (poorly named) "ASP NET 5 Class Library" project (which will be renamed to ".NET Class Library (Cross-platform)" and have attempted to target Core CLR...
After a number of added references, I am left with 2 unresolved references and 1 error.
Below is my project.json file as a reference and 3 compiler errors I have encountered....
Thanks
z.
errors
Error CS0246 The type or namespace name 'StackFrame' could not be found (are you missing a using directive or an assembly reference?) AspNet5ClassLibrary1.ASP.NET Core 5.0 LibLog.cs 379
Error CS0117 'Delegate' does not contain a definition for 'CreateDelegate' AspNet5ClassLibrary1.ASP.NET Core 5.0 LibLog.cs 1910
Error CS1061 'Type' does not contain a definition for 'Assembly' and no extension method 'Assembly' accepting a first argument of type 'Type' could be found (are you missing a using directive or an assembly reference?) AspNet5ClassLibrary1.ASP.NET Core 5.0 LibLog.cs 1919
project.json
{
"version": "1.0.0-*",
"dependencies": {
},
"frameworks": {
"net45": {
"dependencies": {
}
},
"aspnet50": {
"dependencies": {
}
},
"aspnetcore50": {
"dependencies": {
"System.Runtime": "4.0.20-beta-*",
"System.Runtime.Extensions": "4.0.10-beta-*",
"System.Collections": "4.0.10-beta-*",
"System.Console": "4.0.0-beta-*",
"System.Diagnostics.Process": "4.0.0-beta-*",
"System.Diagnostics.Tools": "4.0.0-beta-*",
"System.Diagnostics.Contracts": "4.0.0-beta-*",
"System.Diagnostics.Debug": "4.0.0-beta-*",
"System.Diagnostics.TraceSource": "4.0.0-beta-*",
"System.Diagnostics.FileVersionInfo": "4.0.0-beta-*",
"System.Linq": "4.0.0-beta-*",
"System.Linq.Expressions": "4.0.0-beta-*",
"System.Globalization": "4.0.10-beta-*",
"System.Text.RegularExpressions": "4.0.10-beta-*",
"System.Dynamic.Runtime": "4.0.0-beta-*",
"System.Reflection": "4.0.10-beta-*",
"System.Reflection.Primitives": "4.0.0-beta-*",
"System.Reflection.TypeExtensions": "4.0.0-beta-*",
"System.Reflection.Extensions": "4.0.0-beta-*"
}
}
}
}
When generating documentation using Sandcastle Help File Builder after installing the LibLog.cs, I noticed there were a few missing doc comments. One was on the Logger delegate, the other is a missing Namespace comment.
I'd suggest adding something like this for the namespace comment - adding the version like in the sample would be great (if possible):
/// <summary>
/// Logging mechanism provided by using <see href="https://github.com/damianh/LibLog">LibLog</see>
version 4.2.3. For documentation on how
/// to use, configure, or modify logging in this library, visit the <see href="https://github.com/damianh/LibLog">LibLog Project Site</see>
.
/// </summary>
[CompilerGenerated]
internal class NamespaceDoc
{
}
Great library!
I'm using LibLog as part of an IdentityServer implementation and am using NLog as my logging provider. We need to log a number of custom fields to be able to troubleshoot potential issues with users. NLog allows custom fields with a Properties dictionary and the event-context layout renderer. Is this supported via LibLog?
I don't see anything that would allow this, but I may have missed it.
Thanks so much.
Hi!
I get the following error using Logger.IsDebugEnabled()
ERROR MyUtilities.MyService (null) - Failed to generate log message
System.NullReferenceException: Object reference not set to an instance of an object.
at MyUtilities.Logging.LoggerExecutionWrapper.<>c__DisplayClass2.<Log>b__0()
in c:\...\MyUtilities\App_Packages\LibLog.1.3\Logging.cs:line 330
The code:
public class MyService {
private static readonly ILog Logger = LogProvider.For<MyService>();
public void MyMethod() {
if (Logger.IsDebugEnabled())
Logger.Debug("This is my debug message");
}
}
In v1-3, LogProvider.For<>()
, LogProvider.GetCurrentClassLogger()
and LogProvider.GetLogger()
were public and available to all.
Reports in the field were of people doing var logger = YourLib.Logging.LogProvider.For<>()
in their code causing undesirable coupling.
In v4 the intention was to make them internal to prevent this but there is a scenario where this fails: where people have one solution with several projects and they only want to use one LibLog from their Core
project (and they aren't using [InternalsVisibleTo]
Options are:
public
and add an xml comment something along the lines of "If you don't own this library, it is advisable that you don't calling this."internal
only and encourage [InternalsVisibleTo]
which will have it's own side effects.v4 is delisted pending fixing of this
Ping @SimonCropp @adamralph
Currently we make use of context to set correlation identifiers for all our log requests. Currently this is not supported using LibLog. Do you think this would be a good extension to LibLog?
http://logging.apache.org/log4net/release/manual/contexts.html
http://nblumhardt.com/2013/09/serilog-gets-a-diagnostic-context/
http://nlog-project.org/documentation/v2.0.1/html/T_NLog_MappedDiagnosticsContext.htm
Don't want them leaking on consumer public APIs
App_Packages/LibLog.3.1/LibLog.cs(652,38): error CS0414: Warning as Error: The private field `ScriptCs.Logging.LogProviders.NLogLogProvider.NLogLogger._logger' is assigned but its value is never used
App_Packages/LibLog.3.1/LibLog.cs(871,38): error CS0414: Warning as Error: The private field `ScriptCs.Logging.LogProviders.Log4NetLogProvider.Log4NetLogger._logger' is assigned but its value is never used
Similar to Katana's ILogger signature
e.g.
Logger.InfoFormat("{0}\n {1}", "Client validation success", json);
2015-04-21 15:26:54.160 +02:00 [Information] "Client validation success"
"{
"ClientId": "client",
"ClientName": "Client Credentials Flow Client",
"ClientCredentialType": "SharedSecret"
}"
Does not happen when using Format
and concat the string manually.
I am not sure if you already do this but it is probably valuable for you to setup a custom daily CI build that does a nuget update on all the logging lobs your support and runs through your standard suite of tests. This means as soon as a new incompatible version of any of those libs is released you will know in in an automated way.
All of the log provider tests assert that the correct log message was written by using in-memory logging targets. i.e. NLog and Log4Net.
The LoupeLoggingProviderTests are missing these however.
@kendallmiller can you point me in the direction on how to create a Loupe in-memory target so I can assert the messages? Thx!
Is it me or the default skipLevel in the loupeLogger should be set to 2 ?
With the default setting of 1 i get the all my log locations refer to LigLog.cs
Hi @damianh, thanks for the excellent library. Trying to write a blog about it and created a sample console project with log4net to test it out, but the logger is initialized with level=null
However, the EffectiveLevel
is set correctly to what's configured in the log4net.config file. Please tell me it's something silly I did an not a bug? Happy to supply any files you may need, though the setup is pretty basic. Any help would be really appreciated.
In our solution we use idsrv3 and a few of my own libs that all have used liblog.
From the developer point of view when using multiply libs that use liblog one has to configure at startup the logproviders for all of them.
ns1.Logging.LogProvider.SetCurrentLogProvider(...);
ns2.Logging.LogProvider.SetCurrentLogProvider(...);
ns3.Logging.LogProvider.SetCurrentLogProvider(...);
ns4.Logging.LogProvider.SetCurrentLogProvider(...);
Due to it's not a shared library that is used I need to implement my log provider for each of the using libs since they have their own dll ect. The problem that i have is the enum for loglvl that exists in all libs that use liblog. Maybe someone can do some magic using a primitive type?
If someone has a workaround with reflection that would work for me also.
Example:
public class MultiDiagnosticsTraceLogProvider : ILogProvider,
SInnovations.ConfigurationManager.Logging.ILogProvider,
SInnovations.Azure.MessageProcessor.Core.Logging.ILogProvider,
SInnovations.Azure.TableStorageRepository.Logging.ILogProvider
{
public Logger GetLogger(string name)
{
return new DiagnosticsTraceLogger(name).Log;
}
SInnovations.ConfigurationManager.Logging.Logger SInnovations.ConfigurationManager.Logging.ILogProvider.GetLogger(string name)
{
return new DiagnosticsTraceLogger(name).Log; //this cannot be reused.
}
SInnovations.Azure.MessageProcessor.Core.Logging.Logger SInnovations.Azure.MessageProcessor.Core.Logging.ILogProvider.GetLogger(string name)
{
throw new NotImplementedException();
}
SInnovations.Azure.TableStorageRepository.Logging.Logger SInnovations.Azure.TableStorageRepository.Logging.ILogProvider.GetLogger(string name)
{
throw new NotImplementedException();
}
}
and
public class DiagnosticsTraceLogger : ILog
{
private readonly string _name;
private static string fullPattern = Regex.Replace(DateTimeFormatInfo.CurrentInfo.FullDateTimePattern, "(:ss|:s)", "$1.fff");
public DiagnosticsTraceLogger(string name)
{
this._name = string.Format("[{0}]", name);
}
public bool Log(Ascend.Common.Logging.LogLevel logLevel, Func<string> messageFunc, Exception exception = null, params object[] formatParameters)
{
if (messageFunc != null)
{
if (exception == null)
{
string message = string.Format("{0}: {1} -- {2}", this._name, DateTimeOffset.UtcNow.ToString(fullPattern), string.Format(messageFunc(), formatParameters));
TraceMsg(logLevel, message);
}
else
{
string str2 = string.Format("{0}: {1} -- {2}\n{3}", new object[] { this._name, DateTimeOffset.UtcNow.ToString(fullPattern), string.Format(messageFunc(), formatParameters), exception });
TraceMsg(logLevel, str2);
}
}
return true;
}
private static void TraceMsg(Ascend.Common.Logging.LogLevel logLevel, string message)
{
switch (logLevel)
{
case Ascend.Common.Logging.LogLevel.Trace:
case Ascend.Common.Logging.LogLevel.Debug:
Trace.WriteLine(message, logLevel.ToString());
return;
case Ascend.Common.Logging.LogLevel.Info:
Trace.TraceInformation(message);
return;
case Ascend.Common.Logging.LogLevel.Warn:
Trace.TraceWarning(message);
return;
case Ascend.Common.Logging.LogLevel.Error:
Trace.TraceError(message);
return;
case Ascend.Common.Logging.LogLevel.Fatal:
Trace.TraceError(string.Format("FATAL : {0}", message));
return;
}
}
}
Using NLog, if I reconfigure the logger via code, it seems as if Liblog loses the references it needs in order to build log sinks. No promises, but will try to build a simplistic reproduction of this.
As my library is developing, i'm running into an issue that i do not think i want the users of the library to have to implement... password masking.
In my case, it could be a json string or a connectionString, like you would use for SQL server.
Digging into the source code, it looks like the most practical place to implement the masking would be under LogMessageFormatter.SimulateStructuredLogging(messageFunc, formatParameters) {...}
, and then in the serilog provider {TBD}
.
I have some code that could be a basis of this, if interested (regex may need to be refactored a slight bit, but it is functional).
Experience this in tests
Line 564 in c91f463
Return an no-op disposable instead.
Originally titled 'scriptcs use case'. After discussion, it seems there is a potential for a new feature here so I've updated the title accordingly.
Whether this is just an FYI, a discussion or a proposal for a feature I don't know, but I'm going to leave it here FWIW.
We are in the process of adopting LibLog for scriptcs (elbowing out Common.Logging).
The way logging has been done scriptcs historically is slightly different to most cases. Instead of using static log provision, i.e. private static readonly ILog log = LogProvider.For<Foo>();
etc, we inject logging types via constructors (currently ILog
but we are taking advantage of the breaking change of removing Common.Logging to change to ILogProvider
). When using the core library, it is the responsibility of the consumer to pass an ILogProvider
instance when constructing any objects which demand it. When using the hosting library, an IoC container is used to provide all the services required so an ILogProvider
only needs to be passed once. (There is also an outstanding issue to remove this burden from consumers who don't care by providing an overload which uses a default logger internally.)
The way we have adopted LibLog is to install it in our central Contracts library, which contains chiefly interfaces and some light abstract classes. It is the ILogProvider
interface defined here which is used by all dependent libraries and indeed is the interface designed for consumption by script packs, modules and scripts when they demand an injected instance. I.e. it the officially supported interface for logging in scriptcs. Now, this does immediately couple the ecosystem to LibLog but, if the interfaces change in the future, we accept the burden of deciding whether to propagate the breaking change or hide/customise the LibLog interfaces as we see fit. For convenience, we also expose a DefautLogProvider
which wraps the internal LibLog providers and a NullLogProvider
.
Now, the pros and cons of constructor vs static logging provision can be debated, but it does have the advantage that when a custom logger is specified, as indeed it is when the hosting lib is used from scriptcs.exe, there is no need to adapt and propagate the library specific ILogProvider
to the lower level libs. I did spike conversion of the whole thing to static log provision but I decided to abandon it since logging injection for script packs, modules and scripts is something we do want to support, so ultimately we will always end up doing this using centrally defined logging interaces in the Contracts library. Having each lib with it's own LibLog with all the adaptation required to get a provider all the way down into Contracts and the adaptation to get it back out as a Contracts interface just seemed like complete overkill.
So, the bottom line is, for this use case, we hack out about 60 lines of LibLog to reduce the API to only that which is required to support it. You can see the change here https://github.com/adamralph/scriptcs/commit/2ee8d6916ccd2e9ab855a7517558995fd612d169
To summarise:
LogExtensions
stays public - the removal of the conditional comp there isn't strictly necessaryLogProvider
becomes internalLogProvider
fields and methods are removedWhy am I raising this issue? Good question. I guess I'm looking for opinion on the above and/or a consideration of whether you'd like to support a conditional compilation symbol which could give us just the API required for this use case without having to customise LibLog after installation. I concede that it's likely few projects are using LibLog in this way, but I believe the approach of constructor based log provision, as opposed to static log provision, can be regarded as a general pattern.
</walloftext>
I noticed in 1.4 that the SerilogLogProvider has been moved down the list in
private static ILogProvider ResolveLogProvider()
Would it be possible to move it back up to the top as SeriLog can sit over the top of Log4Net, etc.
While working on another issue I'm seeing a compilation error on this line:
if (formatParameters == null || !formatParameters.Length == 0)
{
return messageBuilder;
}
Due to the ! in front of "formatParameters.Length". The specific compilation error in VS 2013 is:
Error 1 Operator '!' cannot be applied to operand of type 'int' C:\Development\Git\LibLog\src\LibLog\LibLog.cs 1886 45 LibLog
which would be trivial to resolve by wrapping the expression in parenthesis, but I think the logic is wrong - I think the goal was to test for null or zero length in which case the ! is a typo.
This is somehow related to #49 I've opened before.
log4net's NDC and MDC classes which are used by LibLog use the ThreadContext static class (see the implementation).
ThreadContext is implemented using a [ThreadStatic] variable. This doesn't work well with the asyc/await feature since you might return to a different thread than the one you started on.
In order to solve this, we can use log4net's LogicalThreadContext - we just need to use the exact same implementation in the referenced NDC and MDC files, but replace everywhere ThreadContext with LogicalThreadContext.
This will use the CallContext class and therefore will not suffer with async/await issues.
Note that this is the default behavior of Serilog's implementation (see here).
Right now liblog leaks. At the very least there should be a compiler flag like LIBLOG_INTERNAL (tinyioc does this as well)
"I want to just disable console logging, actually all logging, in tests. I'd like Console logger to remain in use in shipped assembly.", paraphrased from @leastprivilege
I propose a public static void LogProvider.Disable()
and that will mean for every subsequent call to GetLogger()
a Noop logger is returned. I can see this being of use to Lib consumers who may just want to turn off logging for a lib they are consuming.
Point of note - this will be static mutable state. This needs to be considered when leveraging parallel testing.
A corresponding public static void LogProvider.Enable()
would be needed also.
Would it be possible to change this so when you pass in a list of object params, it is down to each logging provider to decide how to format the message and parameters/args?
For example, most would use string.Format(CultureInfo.InvariantCulture, message, args)) before writing the message, but for Serilog, you could pass the message and args and it would correctly format the message.
An example (taken from https://github.com/Catel/Catel/blob/develop/src/Catel.Core/Catel.Core.Shared/Logging/Extensions/LogExtensions.debug.cs#L30):
/// <summary>
/// Writes the specified message as debug message.
/// </summary>
/// <param name="log">The log.</param>
/// <param name="messageFormat">The message format.</param>
/// <param name="args">The formatting arguments.</param>
public static void Debug(this ILog log, string messageFormat, params object[] args)
{
string message = messageFormat ?? string.Empty;
if (args != null && args.Length > 0)
{
message = string.Format(message, args);
}
log.Debug(message);
}
When I log data in my application and I want the Method Name and Class Name I'm getting the LibLog data and not my application data - Method Name = Log , and Class Name = LoggerExecutionWrapper.
After some debugging it seems that the problem is in the IsInTypeHierarchy method(line 1213) which returns the wrong result so the Stack Trace includes the LibLog data.
I wrote my own method to check if the types in the Stack Trace are part of the LibLog namespace, if so, I'm creating a new Stack Trace without them.
I'm using LibLog 4.2 + log4net
Thanks
Love the idea behind LibLog.
Would you be open to some changes to avoid unnecessary allocations when a particular log level isn't enabled?
public interface ILog
{
// New
IsTraceEnabled { get; }
IsDebugEnabled { get; }
IsInfoEnabled { get; }
IsWarnEnabled { get; }
IsErrorEnabled { get; }
IsFatalEnabled { get; }
}
public static class LogExtensions
{
public static void Debug(this ILog logger, string message)
{
GuardAgainstNullLogger(logger);
if (logger.IsDebugEnabled) // Avoids allocating the func
{
logger.Log(LogLevel.Debug, () => message);
}
}
// Provide overloads to avoid allocating the params object[] for a common number of arguments
// and use generics to avoid boxing
public static void DebugFormat<T>(this ILog logger, string message, T arg)
{
GuardAgainstNullLogger(logger);
if (logger.IsDebugEnabled)
{
logger.Log(LogLevel.Debug, () => string.Format(CultureInfo.InvariantCulture, message, arg));
}
}
public static void DebugFormat<T1, T2>(this ILog logger, string message, T1 arg1, T2 arg2)
{
GuardAgainstNullLogger(logger);
if (logger.IsDebugEnabled)
{
logger.Log(LogLevel.Debug, () => string.Format(CultureInfo.InvariantCulture, message, arg1, arg2));
}
}
public static void DebugFormat<T1, T2, T3>(this ILog logger, string message, T1 arg1, T2 arg2, T3 arg3)
{
GuardAgainstNullLogger(logger);
if (logger.IsDebugEnabled)
{
logger.Log(LogLevel.Debug, () => string.Format(CultureInfo.InvariantCulture, message, arg1, arg2, arg3));
}
}
}
When creating the ColoredConsoleLogger
example I found that I'd liked to have been able to derive from LogProviderBase
and leverage the LogMessageFormmatter.SimulateStructuredLogging
. Had to re-invent that wheel.
https://msdn.microsoft.com/en-us/library/ff648083.aspx
http://www.codeproject.com/Articles/9545/Get-Logging-with-the-Enterprise-Library
Would love a contrib here (hint hint @mihasic ๐ )
Running code analysis on a solution that is implementing LibLog is bringing up CA1065 because the internal classes (e.g. internal class SerilogLogger
) is throwing an exception during static construction. According to the dialog:
'SerilogLogProvider.SerilogLogger.SerilogLogger()' creates an exception of type 'InvalidOperationException'. Exceptions should not be raised in this type of method. If this exception instance might be raised, change this method's logic so it no longer raises an exception.
Would it be better if we annotate the liblog code with a suppression for this exception, or is there a way to follow the suggestion here and refactor the static constructor to not need to throw an exception?
LibLog's
goal is to provide a simple logging abstract and support for several of the most popular loggers. Of course, all these loggers have console sinks. Does having a ColouredConsoleLogger
step outside LibLog's
remit? Should it, or should it not, be doing any actual output at all (Console, System.Diagnostics, etc)?
I've noticed that both, OpenNestedContext()
and OpenMappedContext()
, return a no-op if CurrentLogProvider
is null. The latter, however, only ever gets set by calling LogProvider.SetCurrentLogProvider()
explicitly. Hence, if I've got code like the example from the Wiki in my library:
public class MyClass
{
private static readonly ILog Logger = LogProvider.For<MyClass>();
public MyClass()
{
using(LogProvider.OpenNestedContext("message"))
using(LogProvider.OpenMappedContext("key", "value"))
{
Logger.Info(....);
}
}
}
... the OpenXXXContext
calls are simply being ignored. I'm wondering now what the suggested usage pattern is. Am I supposed to put a line like this in some init code of my library?
LogProvider.SetCurrentLogProvider(LogProvider.ResolveLogProvider());
I would have expected that CurrentLogProvider
was set implicitly the first time ResolveLogProvider()
gets called. Am I completely misunderstanding something?
I've come across this when I was using a LibLog-enabled library from a log4net client which used a "[%property{NDC}]" conversion pattern - which, however, always returned "[(null)]" until I added the explicit call to SetCurrentLogProvider()
above to the library.
If this is how I am supposed to use LibLog, that's okay, but I didn't find it very intuitive and think it should be documented.
When logging using Seirlog when outputting the $sourcecontext property in the output template its not replacingith correctly with the context
serilog is configured as per
Log.Logger = New LoggerConfiguration() _
.Enrich.With(New ThreadIdEnricher()) _
.Enrich.FromLogContext _
.Enrich.WithMachineName _
.Enrich.WithProcessId _
.MinimumLevel.Is(Events.LogEventLevel.Debug) _
.WriteTo.ColoredConsole(outputTemplate:=logLayout) _
.WriteTo.File(logFileName, outputTemplate:=logLayout) _
.CreateLogger()
outputTemplate is
{Timestamp:HH:mm} [{Level}] ({ThreadId}) ({SourceContext}) {Message}{NewLine}{Exception}
the context should be there eg.
11:01 [Information] (8) (AIMIE.MaintenanceService.Program) OnStart at 03/05/2015 11:01:37
Porting to F# would make a nice up-for-grabs
issue
surce packages that include n langs get the extra files added by default, but only those of languages that can be compiled within the current active project will end up as <Compile Include="
in the .proj
ect file so people typically don't go any further wrt separating out into e.g. having separate source packages per languages.
Ditto VB :P
Not sure if anyone has come across this or not, but am wanting to provide the ability to direct the log output into multiple sinks (e.g. NLog and Elmah). Is there functionality to do this today, and if not, is there any way where we can provide the functionality? Is this even a concern of LibLog, or should this be owned/handled outside of the LibLog context?
Wouldn't that make sense?
I don't need this (yet) but if there is anyone out there who thinks they may need this leave a ๐ In anycase, I have doubts that the reflection / dynamic stuff will work; if so, it would be of limited use.
How can I apply the Xml configuration for the Log4NetProvider?
For example, how to create your own LogProvider.
The use case is that if you have a component B that uses LibLog but also has child components C & D (possibly ILMerged and internalized) that also use LibLog , if consumer A sets B's CurrentLogProvider, then B may wish to forward that LogProvider to C & D.
If C & D are using different versions of LibLog, B will need to adapt accordingly.
given this message "Query language substitutions: {'true'='1', 'false'='0', 'yes'=''Y'', 'no'=''N''}" LogMessageFormatter.SimulateStructuredLogging throws format exception
I think its not a responsibility of a caller to escape {}. This line came from nhibernate. it was tested in 3.1 version.
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.