Weird and very specific question. Right now we have a logging interface that uses the CallerMemberNameAttribute like so:
interface ILogger
{
void Info(string message, [CallerMemberName] string memberName = "");
}
Which is all great and perfect and works fine in our implementation. However, a requirement has come up that we need to write some functions that can be invoked in our process and also elsewhere, and that these functions need to use a defined ITracer class that looks like the following:
interface ITracer
{
void TraceInformation(string message);
}
So when run in our environment, these functions should log to our current logging infra, but when run in the other environment, it has it's own ITracer set that does its own thing. So I wrote a shim that just passes the messages through when called in our environment:
class Logger : ILogger
{
public void Info(string message, [CallerMemberName] string memberName = "") => // log some stuff
public ITracer GetTraceWriter() => return new TraceWriter(this);
}
class TraceWriter : ITracer
{
public TraceWriter(ILogger logger) => this.logger = logger;
public void TraceInformation(string message) => this.logger.Info($"{message}");
}
This works fine, but the memberName is part of the log message that is output, and with this implementation, when the TraceWriter starts logging, it always has the memberName equal to TraceInformation. Is there a way I can pass this parameter attribute through the function call somehow? The main issue here is that I cannot change the ITracer interface.
Solutions thought of but can't get to work:
Change the TraceInformation call in ITracer to return a function call to ILogger.Info that could be invoked directly from the method (Cannot do this because I cannot change the ITracer interface)
Something you could do, which may or may not be ideal, would be to use the StackFrame class to look up the stack to the calling function.
You can use this to iterate through the stack to either find (or exclude) specific types, or perhaps types that implement a specific interface - or more simply to just 'up' the stack a specific number of frames.
If you included this in your implementation of void Info(..) you could access method names as
# get the name of the current method (i.e. Info)
new StackFrame(0, false).GetMethod().Name
# get the name of the calling method (i.e. TraceInformation)
new StackFrame(1, false).GetMethod().Name
# get the name of the parent calling method - what you are looking for
new StackFrame(2, false).GetMethod().Name
Of course, you then need to reconcile when the method is called from the ITracer object and when it is called directly. You could also get calling objects, inspect what interfaces they implement, and record appropriate method name.
This all uses reflection so you will need to consider performance impact, however I expect that CallerMemberName also uses reflection / may have similar impact.
Related
Given the following middleware:
public class RequestDurationMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestDurationMiddleware> _logger;
public RequestDurationMiddleware(RequestDelegate next, ILogger<RequestDurationMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
var watch = Stopwatch.StartNew();
await _next.Invoke(context);
watch.Stop();
_logger.LogTrace("{duration}ms", watch.ElapsedMilliseconds);
}
}
Because of the pipeline, it occurs before the end of pipeline and logs different times:
WebApi.Middlewares.RequestDurationMiddleware 2018-01-10 15:00:16.372 -02:00 [Verbose] 382ms
Microsoft.AspNetCore.Server.Kestrel 2018-01-10 15:00:16.374 -02:00 [Debug] Connection id ""0HLAO9CRJUV0C"" completed keep alive response.
Microsoft.AspNetCore.Hosting.Internal.WebHost 2018-01-10 15:00:16.391 -02:00 [Information] "Request finished in 405.1196ms 400 application/json; charset=utf-8"
How can I capture the actual request execution time from WebHost (405.1196ms in the example) value in this case? I want to store this value in database or use it elsewhere.
I thought this question was really interesting, so I looked into this for a bit to figure out how the WebHost is actually measuring and displaying that request time. Bottom line is: There is neither a good nor an easy nor a pretty way to get this information, and everything feels like a hack. But follow along if you’re still interested.
When the application is started, the WebHostBuilder constructs the WebHost which in turn creates the HostingApplication. That’s basically the root component that is responsible to respond to incoming requests. It is the component that will invoke the middleware pipeline when a request comes in.
It is also the component that will create HostingApplicationDiagnostics which allows to collect diagnostics about the request handling. At the beginning of the request, the HostingApplication will call HostingApplicationDiagnostics.BeginRequest, and at the end of the request, it will call HostingApplicationDiagnostics.RequestEnd.
Not that surprisingly, HostingApplicationDiagnostics is the thing that will measure the request duration and also log that message for the WebHost that you have been seeing. So this is the class that we have to inspect more closely to figure out how to get the information.
There are two things the diagnostics object uses to report diagnostics information: A logger, and a DiagnosticListener.
Diagnostic listener
The DiagnosticListener is an interesting thing: It is basically a general event sink that you can just raise events on. And other objects can then subscribe to it to listen to these events. So this almost sounds perfect for our purpose!
The DiagnosticListener object that the HostingApplicationDiagnostics uses is passed on by the WebHost and it actually gets resolved from dependency injection. Since it is registered by the WebHostBuilder as a singleton, we can actually just resolve the listener from dependency injection and subscribe to its events. So let’s just do that in our Startup:
public void ConfigureServices(IServiceCollection services)
{
// …
// register our observer
services.AddSingleton<DiagnosticObserver>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
// we inject both the DiagnosticListener and our DiagnosticObserver here
DiagnosticListener diagnosticListenerSource, DiagnosticObserver diagnosticObserver)
{
// subscribe to the listener
diagnosticListenerSource.Subscribe(diagnosticObserver);
// …
}
That’s already enough to get our DiagnosticObserver running. Our observer needs to implement IObserver<KeyValuePair<string, object>>. When an event occurs, we will get a key-value-pair where the key is an identifier for the event, and the value is a custom object that is passed by the HostingApplicationDiagnostics.
But before we implement our observer, we should actually look at what kind of events HostingApplicationDiagnostics actually raises.
Unfortunately, when the request ends, the event that is raised on the diagnostic lister just gets passed the end timestamp, so we would also need to listen to the event that is raised at the beginning of the request to read the start timestamp. But that would introduce state into our observer which is something we want to avoid here. In addition, the actual event name constants are prefixed with Deprecated which might be an indicator that we should avoid using these.
The preferred way is to use activities which are also closely related to the diagnostic observer. Activities are apparently states that track, well, activities as they appear in the application. They are started and stopped at some point, and also already record how long they run on their own. So we can just make our observer listen to the stop event for the activity to get notified when its done:
public class DiagnosticObserver : IObserver<KeyValuePair<string, object>>
{
private readonly ILogger<DiagnosticObserver> _logger;
public DiagnosticObserver(ILogger<DiagnosticObserver> logger)
{
_logger = logger;
}
public void OnCompleted() { }
public void OnError(Exception error) { }
public void OnNext(KeyValuePair<string, object> value)
{
if (value.Key == "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop")
{
var httpContext = value.Value.GetType().GetProperty("HttpContext")?.GetValue(value.Value) as HttpContext;
var activity = Activity.Current;
_logger.LogWarning("Request ended for {RequestPath} in {Duration} ms",
httpContext.Request.Path, activity.Duration.TotalMilliseconds);
}
}
}
Unfortunately there is just no solution without downsides… I found this solution to be very inaccurate for parallel requests (e.g. when opening a page that has also images or scripts which are requested in parallel). This is likely due to the fact that we are using a static Activity.Current to get the activity. However there does not really seem to be a way to get just the activity for a single request, e.g. from the key value pair that was passed.
So I went back and tried my original idea again, using those deprecated events. The way I understood it is btw. that they are just deprecated because using activities is recommended, not because they will be removed soon (of course we are working with implementation details and an internal class here, so these things could change at any time). To avoid problems with concurrency, we need to make sure we store the state inside of the HTTP context (instead of a class field):
private const string StartTimestampKey = "DiagnosticObserver_StartTimestamp";
public void OnNext(KeyValuePair<string, object> value)
{
if (value.Key == "Microsoft.AspNetCore.Hosting.BeginRequest")
{
var httpContext = (HttpContext)value.Value.GetType().GetProperty("httpContext").GetValue(value.Value);
httpContext.Items[StartTimestampKey] = (long)value.Value.GetType().GetProperty("timestamp").GetValue(value.Value);
}
else if (value.Key == "Microsoft.AspNetCore.Hosting.EndRequest")
{
var httpContext = (HttpContext)value.Value.GetType().GetProperty("httpContext").GetValue(value.Value);
var endTimestamp = (long)value.Value.GetType().GetProperty("timestamp").GetValue(value.Value);
var startTimestamp = (long)httpContext.Items[StartTimestampKey];
var duration = new TimeSpan((long)((endTimestamp - startTimestamp) * TimeSpan.TicksPerSecond / (double)Stopwatch.Frequency));
_logger.LogWarning("Request ended for {RequestPath} in {Duration} ms",
httpContext.Request.Path, duration.TotalMilliseconds);
}
}
When running this, we do actually get accurate results and we also have access to the HttpContext which we can use to identify the request. Of course, the overhead that’s involved here is very apparent: Reflection to access property values, having to store information in HttpContext.Items, the whole observer thing in general… that’s probably not a very performant way to do this.
Futher reading on diagnostic source and activities: DiagnosticSource Users Guid and Activity User Guide.
Logging
Somewhere above I mentioned that the HostingApplicationDiagnostics also reports the information to the logging facilities. Of course: This is what we are seeing in the console after all. And if we look at the implementation, we can see that this already calculates the proper duration here. And since this is structured logging, we could use this to grab that information.
So let’s attempt to write a custom logger that checks for that exact state object and see what we can do:
public class RequestDurationLogger : ILogger, ILoggerProvider
{
public ILogger CreateLogger(string categoryName) => this;
public void Dispose() { }
public IDisposable BeginScope<TState>(TState state) => NullDisposable.Instance;
public bool IsEnabled(LogLevel logLevel) => true;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (state.GetType().FullName == "Microsoft.AspNetCore.Hosting.Internal.HostingRequestFinishedLog" &&
state is IReadOnlyList<KeyValuePair<string, object>> values &&
values.FirstOrDefault(kv => kv.Key == "ElapsedMilliseconds").Value is double milliseconds)
{
Console.WriteLine($"Request took {milliseconds} ms");
}
}
private class NullDisposable : IDisposable
{
public static readonly NullDisposable Instance = new NullDisposable();
public void Dispose() { }
}
}
Unfortunately (you probably love this word by now, right?), the state class HostingRequestFinishedLog is internal, so we cannot use it directly. So we have to use reflection to identify it. But we just need its name, then we can extract the value from the read-only list.
Now all we need to do is register that logger (provider) with the web host:
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
logging.AddProvider(new RequestDurationLogger());
})
.UseStartup<Startup>()
.Build();
And that’s actually all we need to be able to access the exact same information that the standard logging also has.
However, there are two problems: We don’t have a HttpContext here, so we cannot get information about which request this duration actually belongs to. And as you can see in the HostingApplicationDiagnostics, this logging call is actually only made when the log level is at least Information.
We could get the HttpContext by reading the private field _httpContext using reflection but there is just nothing we can do about the log level. And of course, the fact that we are creating a logger to grab information from one specific logging call is a super hack and probably not a good idea anyway.
Conclusion
So, this is all terrible. There simply is no clean way to retrieve this information from the HostingApplicationDiagnostics. And we also have to keep in mind that the diagnostics stuff actually only runs when it’s enabled. And performance critical applications will likely disable it at one point or another. In any way, using this information for anything outside of diagnostics would be a bad idea since it’s just too fragile in general.
So what is the better solution? A solution that works outsid of a diagnostics context? A simple middleware that runs early; just like you have already used. Yes, this is likely not as accurate as it will leave out a few paths from the outer request handling pipeline but it will still be an accurate measurement for the actual application code. After all, if we wanted to measure framework performance, we would have to measure it from the outside anyway: as a client, making requests (just like the benchmarks work).
And btw. this is also how Stack Overflow’s own MiniProfiler works. You just register the middleware early and that’s it.
Say I have extensions to ILog. Currently when I use ILog extensions in my buisness logic I see %method %location %class properties as my Extension class ones. I want tham to be refrences to my business logic. Are there in log4net attributes to make ILog extensions hidden?
For example
using log4net;
namespace Helpers {
public class MyObject {}
public static class LoggerExtensions {
public static void Debug(this ILog log, MyObject obj, string format, params object[] arguments) {
log.DebugFormat(format, arguments);
}
}
}
for this <conversionPattern value="%type %method %m%n" /> would return something like: LoggerExtensions Debug message and log4net would not care from where it was invoked.
I need some attribute to make this extension transparent for log4net stackTrace inspector. Is there any or how to create one?
You should be able to do something like this (note that I don't have time right now to test this)...
using log4net;
namespace Helpers
{
public class MyObject {}
public static class LoggerExtensions
{
public static void Debug(this ILog log, MyObject obj, string format, params object[] arguments)
{
if (!log.IsDebugEnabled) return;
log.Logger.Log(typeof(LoggerExtensions), LogLevel.Debug, string.Format(format, arguments));
}
}
}
The key to getting the right call site logged (i.e. where you call your extension method, not the extension method itself) is to use the "Log" method, passing it the type of your object where your logging extension is implemented. Log4net will traverse up the stack until it gets to a type that is the same as the type passed to Log. Some refer to this type as the boundary type. The next entry up on the stack will be the actual call site in your "real" code, not your logging code.
Note also that I check to see if debug logging is enabled and return early if not. The Log method does not have a signature that takes a format and params arguments, so the message must be formatted before calling Log. We don't want to spend the cost to format the message unless it will actually be logged.
As I said earlier, I have not tested this, but this technique is used when wrapping a log4net logger (for example in Common.Logging .Net) to ensure that the call site is maintained. If you look for lot4net wrappers (or NLog wrappers) here on SO, the vast majority are not written such that the call site is maintained, so beware. If you want to wrap or to hide log4net behind an extension method, you cannot simply delegate to the Debug, Info, etc methods. You must use the Log method so that you can pass the boundary type.
Good luck!
Unity Interception can be used to intercept method, and it can capture the values of parameters of the intercepted method.
What I want is to log values of local variables within the intercepted method. For example
Update
public void CopyBlogPost(int id){
var oldblogPost = GetBlogPost(id);
//log details about old blog post, including name, date, id etc.
//copy post
//log details about new blog post, including name, date, id etc.
}
Is there tool that I can use for this scenario?
Update
As #Aron suggests, Mono.Cecil might provide the functionality.
What you can do is define a decorator like this:
public class LoggingCalculatorDecorator : ICalculator
{
private readonly ICalculator decoratee;
private readonly ILogger logger;
public LoggingCalculatorDecorator(
ICalculator decoratee,
ILogger logger)
{
this.decoratee = decoratee;
this.logger = logger;
}
public void Add(int i, int j)
{
var logging = "adding "+i+" "+j;
//Log logging variable, or any local variables
// call decoratee
this.decoratee.Add(i, j);
}
}
This way you can add this behavior to the existing class without having it to change. If you find yourself adding many logging decorators throughout the system (and violating the DRY principle), you are probably missing a common abstraction in the system. Take a look at this and this article. They might you some clues about how to design your system in a way that you don't have to fallback to interception and code weaving, but address the problems at the core: the design of your application.
I have this C# ASP.NET 4 website.
I would like to have a general method in a class which will include a Response.Redirect or Server.Transfer in it to a specific page.
Both names, Response and Server, does not exist in the context.
How to work this around?
as for the comment by #Maess, please consider something like this (edited):
ASPX:
<asp:Button onclick="MyClass.btnRedirect_Click" ID="btnMyButton" Text="MyButtonText" runat="server" />
Code behind:
public static void btnRedirect_Click(object sender, EventArgs e)
{
Response.Redirect("~/SomePage.aspx");
}
You'll find these as properties within HttpContext.Current
You can use System.Web.HttpContext.Current, but be careful. If there is no HTTP context at the time these methods are called you will get an exception.
It is probably safer to have these classes either require an HttpContext in the constructor or have the methods that require an HttpContext to have them in the method signature.
For instance, maybe you have a class which needs to redirect as you mentioned. Your method signature might look like this: public void CustomRedirect(HttpContext context) then within the body of your signature you would do something like this: context.Response.Redirect("..."). Basically, you make the class or method dependent upon having an HttpContext.
Don't directly reference anything involving the HTTP/IIS stack if you're ever going to be called outside of it.
Your best bet is probably to have your class or method accept either a delegate or an object that implements an interface provided by the calling code. When you're ready to redirect, call that delegate/interface method with the URI (or enough information to construct it) and then the calling code can respond with a server.transfer, a response.redirect or a passing unit test.
public static void ButtonRedirect()
{
MyClass foo = new MyClass(delegate(string s) { Server.Transfer(s); });
foo.DoThings();
}
public class MyClass
{
private Action<string> redirector;
public MyClass(Action<string> redirectAction)
{
redirector = redirectAction;
}
public void DoThings()
{
//Doing stuff
//Aha! this should redirect
redirector("/go/to/here");
}
}
I was asked to implement castle dynamic proxy in my asp.net web application and i was going through couple of articles which i got from Castle Project and Code Project about castle dynamic proxy in asp.net web application....
Both articles delt with creating interceptors but i can't get the idea why interceptors are used with classes.... Why should i intercept my class which is behaving properly?
Let's say that your class needs to do 3 things for a certain operation:
Perform a security check;
Log the method call;
Cache the result.
Let's further assume that your class doesn't know anything about the specific way you've configured your security, logging, or caching. You need to depend on abstractions of these things.
There are a few ways to go about it. One way would be to set up a bunch of interfaces and use constructor injection:
public class OrderService : IOrderService
{
private readonly IAuthorizationService auth;
private readonly ILogger logger;
private readonly ICache cache;
public OrderService(IAuthorizationService auth, ILogger logger,
ICache cache)
{
if (auth == null)
throw new ArgumentNullException("auth");
if (logger == null)
throw new ArgumentNullException("logger");
if (cache == null)
throw new ArgumentNullException("cache");
this.auth = auth;
this.logger = logger;
this.cache = cache;
}
public Order GetOrder(int orderID)
{
auth.AssertPermission("GetOrder");
logger.LogInfo("GetOrder:{0}", orderID);
string cacheKey = string.Format("GetOrder-{0}", orderID);
if (cache.Contains(cacheKey))
return (Order)cache[cacheKey];
Order order = LookupOrderInDatabase(orderID);
cache[cacheKey] = order;
return order;
}
}
This isn't horrible code, but think of the problems we're introducing:
The OrderService class can't function without all three dependencies. If we want to make it so it can, we need to start peppering the code with null checks everywhere.
We're writing a ton of extra code to perform a relatively simple operation (looking up an order).
All this boilerplate code has to be repeated in every method, making for a very large, ugly, bug-prone implementation.
Here's a class which is much easier to maintain:
public class OrderService : IOrderService
{
[Authorize]
[Log]
[Cache("GetOrder-{0}")]
public virtual Order GetOrder(int orderID)
{
return LookupOrderInDatabase(orderID);
}
}
In Aspect Oriented Programming, these attributes are called Join Points, the complete set of which is called a Point Cut.
Instead of actually writing dependency code, over and over again, we leave "hints" that some additional operations are supposed to be performed for this method.
Of course, these attributes have to get turned into code sometime, but you can defer that all the way up to your main application code, by creating a proxy for the OrderService (note that the GetOrder method has been made virtual because it needs to be overridden for the service), and intercepting the GetOrder method.
Writing the interceptor might be as simple as this:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (Attribute.IsDefined(invocation.Method, typeof(LogAttribute))
{
Console.Writeline("Method called: "+ invocation.Method.Name);
}
invocation.Proceed();
}
}
And creating the proxy would be:
var generator = new ProxyGenerator();
var orderService = (IOrderService)generator.CreateClassProxy(typeof(OrderService),
new LoggingInterceptor());
This is not only a lot less repetitive code, but it completely removes the actual dependency, because look what we've done - we don't even have an authorization or caching system yet, but the system still runs. We can just insert the authorization and caching logic later by registering another interceptor and checking for AuthorizeAttribute or CacheAttribute.
Hopefully this explains the "why."
Sidebar: As Krzysztof Koźmic comments, it's not a DP "best practice" to use a dynamic interceptor like this. In production code, you don't want to have the interceptor running for unnecessary methods, so use an IInterceptorSelector instead.
The reason you would use Castle-DynamicProxy is for what's called Aspect Orientated Programming. It lets you interject code into the standard operation flow of your code without the need to become dependent on the code itself.
A simple example is as always, logging. That you would create a DynamicProxy around a class that you have errors from that it logs the data going into the method and catches any exceptions and then logs the exception.
Using the intercepter your current code has no idea it exists (assuming you have your software built in a decoupled way with interfaces correctly) and you can change the registration of your classes with an inversion of control container to use the proxied class instead without having to change a single line else where in code. Then when you solve the bug you can turn off the proxying.
More advanced usage of proxying can be seen with NHibernate where all of the lazy loading is handled through proxies.