Serilog.Sinks.Email - No Indication of Failure? - serilog

I've been working with Serilog.Sinks.Email, and I notice that (other than the fact that I don't get an email), there is no exception or anything that indicates a failure when I execute the Log statement. Even if I put in junk for the MailServer, the Log statement executes as though it were successful.
I've tried the SelfLog statement, but see nothing in my Output window from that.
Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));
I've added SymbolSource (http://www.symbolsource.org/Public/Wiki/Using), and am able to step through Serilog's code, but once again, no exceptions are caught.
Does Serilog really give no indication of error, or am I missing something?
Using: .NET Framework 4.6.2, Serilog 2.8, Serilog.Sinks.Email 2.3
Sample Code:
Log.Logger = new LoggerConfiguration()
.WriteTo.Email(new EmailConnectionInfo
{
FromEmail = "xxx",
ToEmail = "xxx",
MailServer = "smtp.xxx.com",
EmailSubject = "My Test"
}
).CreateLogger();
Log.ForContext<Program>().Error("Test Number {Parm}", "1");

Writing to a Serilog logger is supposed to be a safe operation and never throw exceptions, by design, thus any exceptions that happen when sending the e-mail would only appear in the SelfLog - in your case, it would write to the Debug console.
Now, the reason you're not even seeing exceptions in the SelfLog is because e-mails sent via Serilog.Sinks.Email are sent asynchronously, and your program is terminating before the the Sink had the opportunity to send the e-mail.
Before your program terminates, you need to call Log.CloseAndFlush() so that all logs can be sent, before the app closes.
static void Main(string[] args)
{
Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg));
Log.Logger = new LoggerConfiguration()
.WriteTo.Email(...)
.CreateLogger();
try
{
Log.ForContext<Program>().Error("Test Number {Parm}", "1");
// ...
}
finally
{
Log.CloseAndFlush();
}
}
That will allow you to see the error messages you're writing via SelfLog.
You can read more about that in the documentation: Lifecycle of Loggers.
ps: If the operation you're logging is important enough that you'd want to guarantee it succeeds (or throw exception if it doesn't) then you should use Audit Logging, i.e. Use .AuditTo.Email(...) instead of .WriteTo.Email(...)

Related

Queue debug log messages and dump when a error message is logged

In normal setup you only log Information and lower issues, but when an error has occurred and has been logged it's very handy when you also have the Debug log messages.
Is it currently possible to so something like this:
Log.Logger = new LoggerConfiguration()
.Enrich.WithCorrelationId()
// ...other configuration...
.CreateLogger();
normal flow:
log.Debug(...)
...
Exception:
log.Error(ex, ...)
If the minimum level is Information, queue all the Debug log messages (for example with the current CorrelationId or some other scoped variable) and when log.Error is called you can also dump the logged messages with a lower level.
Thanks
Marco
Serilog.Sinks.Buffer might be what you're after.
From that README:
Log.Logger = new LoggerConfiguration()
.UseLogBuffer(("*", LogEventLevel.Information, LogEventLevel.Debug))
.WriteTo(lc => lc.WriteTo.Console())
.CreateLogger();
The package uses buffer scopes rather than correlation ids to control which events are emitted when a trigger occurs:
using (LogBuffer.BeginScope())
{
// ...
}

Messages not reaching destination queue when using ServerInitializerFactory Netty 4

I am using apache camel netty4 in grails and I have declared mycustom ServerInitializerFactory as follows
public class MyServerInitializerFactory extends ServerInitializerFactory {
private int maxLineSize = 1048576;
NettyConsumer nettyConsumer
public MimacsServerInitializerFactory() {}
#Override
protected void initChannel(Channel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline()
pipeline.addLast("logger", new LoggingHandler(LogLevel.INFO))
pipeline.addLast("framer", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, maxLineSize, 2, 2, 6, 0, false))
pipeline.addLast("decoder", new MfuDecoder())
pipeline.addLast("encoder", new MfuEncoder())
pipeline.addLast("handler", new MyServerHandler())
}
}
I have a route which I setup as follows in my routebuilder.
from('netty4:tcp://192.168.254.3:553?serverInitializerFactory=#sif&keepAlive=true&sync=true&allowDefaultCodec=false').to('activemq:queue:Tracking.Queue')
My Camel Context is setup in the BootStrap.groovy as follows
def serverInitializerFactory = new MyServerInitializerFactory()
SimpleRegistry registry = new SimpleRegistry()
registry.put("sif", serverInitializerFactory)
CamelContext camelContext = new DefaultCamelContext(registry)
camelContext.addComponent("activemq", activeMQComponent.activeMQComponent("failover:tcp://localhost:61616"))
camelContext.addRoutes new TrackingMessageRoute()
camelContext.start()
When I run my app, my route is started and my framer, decoder, handler and encoders are all invoked but messages do not reach the Tracking. Queue and responses do not get back to the client.
If I do not use serverInitializerFactory in the netty url and user encoders and decoders instead, My messages are hitting the queue but I lose control of the acknowledgement that I want to sent for each type of message that I receive. It seems activemq tries to sent its own response which is rejected by my encoder.
Am I supposed to then write code to send again or is there something I am missing?
You need to add a handler with the consumer so it can be routed, see the unit test how its done:
https://github.com/apache/camel/blob/master/components/camel-netty4/src/test/java/org/apache/camel/component/netty4/NettyCustomPipelineFactoryAsynchTest.java#L112
I managed to get around that problem. In my channelRead0 method. I added the following lines
Exchange exchange = this.consumer.getEndpoint().createExchange(ctx, msg);
where ctx is the ChannelContextHandler and msg is the Message Object, the two are both parameters of the channelRead0 method.
I also added the following lines
this.consumer.createUoW(exchange);
and after my handling code I inserted the following line
this.consumer.doneUoW(exchange);
and everything works like a charm.

Web API, async file uploading works locally, not on server

Using the following tutorial: http://www.asp.net/web-api/overview/working-with-http/sending-html-form-data,-part-2, I used the following controller for the base of a file upload call I implemented:
public Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
// Read the form data and return an async task.
var task = Request.Content.ReadAsMultipartAsync(provider).
ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
}
// A whole lotta logic to save the file, process it, etc.
});
return task;
}
To save on space I didn't include the majority of the logic I wrote, since the error happens on the first line within of ContinueWith,
if (t.IsFaulted || t.IsCanceled)
If I run this locally from VS2010, both of the above booleans are false, and the code works perfectly - all of it, even extra few dozen lines I commented out. When I deploy it to a server running IIS7, t.IsFaulted is always true. I've never worked with asynchronous calls in C#, and have only done a few simple controllers in Web API...is there something I have to install/configure/etc. on a production server to make it work?
Making it more difficult is the fact that all of the exceptions that are occurring stay in that task (i.e. don't get caught by ELMAH), so I've no idea how to debug what's happening; IIS is also not logging any errors that are occurring in the event viewer...so I'm at a loss to know exactly what's going on. Any tips on how to make this debugging process easier?

FluentNhibernate configuration exception handling in application_start

I am initializing FluentNHibernate from Application_Start event like so:
Fluently.Configure()
.Database(OracleDataClientConfiguration.Oracle10
.Driver<NHibernate.Driver.OracleDataClientDriver>()
.ConnectionString("MyConnectionString")
.DefaultSchema("MySchema")
)
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<SomeClass>())
.BuildConfiguration()
.BuildSessionFactory();
If the connection string is bad, or connection to the DB fails for some other reason, I get a TNS No listener exception. I would like to display/log this exception but Application_Start (and Applicaiton_Error) doesn't have an HttpContext or Response object in IIS7 Integrated mode. The user gets a yellow screen of death telling them to turn custom errors On. Elmah doesn't log the message either. I would like to solve the problem in one of two possible ways:
Disable nhibernate configuration from connecting to the database on configuration.
Provide custom user feedback based on the error and get Elmah working (somehow). This would be my ideal choice.
I was able to move NHibernate configuration to run on Session_Start, as described here, which gets exception handling working for this error, but then I get other exceptions that can be misleading to the root cause of the problem. Does anyone have a good solution for this scenario?
Thank you.
This is what I do:
void Application_Start() {
try {
// setup your app / nhibernate
} catch(Exception ex) {
Application["StartupError"] = ex
}
}
void Application_BeginRequest() {
var startupError = Application["StartupError"] as Exception;
if (startupError != null)
throw new Exception("Error starting application", startupError);
}
In your BeginRequest method you have access to the Request and can do what you want to show the error (or show a nice page)

ELMAH error logging for Windows Service

We are using ELMAH to log the web application exception which works great!. Also we want to know how to customize ELMAH to log the windows service exception.
I am not interested in using another application for logging only windows service exception.
Any help would be appreciated.
I did this previously. I found out the code to use by digging though the source code starting from the ErrorSignal.FromCurrentContext().Raise(ex); method.
This currently only logs to the Database (as thats all i needed) but with a little bit more investigation you could write a wrapper method that logs to whatever you have set-up in the config file.
try
{
Elmah.SqlErrorLog ErrorLog = new Elmah.SqlErrorLog(ConfigurationManager.ConnectionStrings["Default"].ConnectionString);
ErrorLog.ApplicationName = "AppName";
ErrorLog.Log(new Elmah.Error(new Exception("example")));
}
catch (Exception ex)
{
//catch sql error
}
In my service I made the ErrorLog variable a public singleton object that was easily accessed from the service project.
you can use it
Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(new Exception("Error text")));

Resources