Setting up etw logs in azure table with mvc - c#

Spent more than 4 hours trying to figure out why etw logs wont show up in my tables. I still am unable to figure out why my logs are not showing up in azure table.
EDIT
The service is hosted as cloud service.
Here is how my diagnostics xml looks like. This is auto generated by selecting options in visual studio
<?xml version="1.0" encoding="utf-8"?>
<DiagnosticsConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
<PublicConfig xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
<WadCfg>
<DiagnosticMonitorConfiguration overallQuotaInMB="4096">
<EtwProviders>
<EtwEventSourceProviderConfiguration provider="AzureEventSource">
<Event id="1" eventDestination="Error" />
<Event id="2" eventDestination="Warning" />
<Event id="3" eventDestination="Debug" />
<Event id="4" eventDestination="Performance" />
<DefaultEvents eventDestination="Default" />
</EtwEventSourceProviderConfiguration>
</EtwProviders>
<Logs scheduledTransferPeriod="PT2M" />
</DiagnosticMonitorConfiguration>
</WadCfg>
<StorageAccount />
</PublicConfig>
<PrivateConfig xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
<StorageAccount endpoint="" />
</PrivateConfig>
<IsEnabled>true</IsEnabled>
</DiagnosticsConfiguration>
This is how my class looks like
using Microsoft.Diagnostics.Tracing;
namespace CommonUtils
internal sealed class AzureEventSource : EventSource, ILogger
{
public AzureEventSource(Type owner) : base(owner.FullName)
{
}
private bool IsInputInvalid(String message)
{
return String.IsNullOrWhiteSpace(message);
}
public void Error(string message, params object[] args)
{
if (IsInputInvalid(message))
{
throw new ArgumentNullException("message");
}
this.WriteEvent(1, string.Format(message, args));
}
}
}
I am pretty sure I am missing something simple.
Any help will be greatly appreciated

Assuming you're referring to Microsoft.Diagnostics.Tracing.EventSource in your above example.
You're missing EventSource Event attributes for your class and method respectively.
A simple hello world of eventsource looks like this.
[EventSource(Name = "HelloEventSource")]
internal sealed class HelloEventSource : EventSource
{
[Event(1, Level = EventLevel.Informational, Message = "Hello World! {0}")]
public void HelloWorld(string name)
{
WriteEvent(1, name);
}
}
You should fix the tracing part of your code and check the logs are getting generated locally on your machine/vm.
Sending the events via diagnostics pipeline of your choice comes next.

Related

Receiving eBay SOAP notification messages

I am trying to receive notifications using ebay and their SDK. I have managed to find a working example using an ASP.net web service. However I want to be able to host this on Azure and moving this to a WCF seems like a suitable solution. I have tried doing so and the closest I have got is getting a xml serializer error like below:
The server encountered an error processing the request. The exception message is 'Unable to deserialize XML body with root name 'Envelope' and root namespace 'http://schemas.xmlsoap.org/soap/envelope/' (for operation 'GetOutBid' and contract ('IReceiver', 'urn:ebay:apis:eBLBaseComponents')) using XmlSerializer. Ensure that the type corresponding to the XML is added to the known types collection of the service.'
From what I have seen online, looks like it could be to do with how the datacontract should be setup - I'm new to WCF, so not sure!
Below is what is working in the web service which I'm trying to put into WCF:
[WebMethod()]
[System.Web.Services.Protocols.SoapHeaderAttribute("RequesterCredentials", Direction = System.Web.Services.Protocols.SoapHeaderDirection.In)]
[System.Web.Services.Protocols.SoapDocumentMethodAttribute(Action = "http://developer.ebay.com/notification/OutBid", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Bare)]
public void OutBid(GetItemResponseType GetItemResponse)
{
if (CheckSignature(GetItemResponse.Timestamp))
{
//Implement your own business logic here
}
else
{
//Implement your own business logic here
}
LogRequest(Server.MapPath("files/OutBid_" + GetItemResponse.Item.ItemID + "_" + GetItemResponse.Item.SellingStatus.BidCount.ToString() + "_" + GetItemResponse.CorrelationID + ".xml"));
}
public class student { public int rollno { get; set; } }
public class school { public student obj { get; set; } }
class Program
{
static void Main(string[] args)
{
school obje = new school(); obje.obj.rollno = 2; Console.WriteLine(obje.obj.rollno);
}
}
Based on your code, I found that the protocol between the service and client is SOAP. To support SOAP, we need to use basicHttpBinding in WCF. The protocolMapping configuration section in web.config should be like this.
<protocolMapping>
<add binding="basicHttpBinding" scheme="http"/>
</protocolMapping>
After that, we could define the service contact and service to handle requests.
The service contact could be like this.
[ServiceContract]
public interface IService1
{
[OperationContract(Action= "http://developer.ebay.com/notification/OutBid")]
string OutBid(school value);
}
A sample of Service.
public class Service1 : IService1
{
public string OutBid(school value)
{
return string.Format("The rollno is {0}", value.obj.rollno);
}
}
Following are my test results.
Sample request.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://developer.ebay.com/notification/OutBid</Action>
</s:Header>
<s:Body>
<OutBid xmlns="http://tempuri.org/">
<value xmlns:d4p1="http://schemas.datacontract.org/2004/07/TestSOAP" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:obj>
<d4p1:rollno>2</d4p1:rollno>
</d4p1:obj>
</value>
</OutBid>
</s:Body>
</s:Envelope>
Sample result.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body>
<OutBidResponse xmlns="http://tempuri.org/">
<OutBidResult>The rollno is 2</OutBidResult>
</OutBidResponse>
</s:Body>
</s:Envelope>
If you can't finish the work on your side, please post your sample XML request content for further discussion.

EventSourcing with NServiceBus Subscribe to all Events

I want use NServiceBus with GetEventStore to create CQRS/EventSourcing solution.
I have a set of Events each is stamped with Aggregate type name and Aggregate id. My domain publishes events using NServiceBus. All events derive from one base type.
I want create message handler which subscribes to all events published by domain, so it can save events in EventStore.
I tried subscribe to my base Event but it doesn't work.
Is there any way to subscribe to all types of events? I don't also want to change NServiceBus configuration or add new handler in my EventStore worker each time I create new domain Event.
I've managed to solve the problem. I have a base Event class and I publish events that derive from the base Event class. On my subscriber I subscribe to base Event and Handle method is firing every time derived event is published.
Messages project
public class Event : IEvent
{
}
public class Event1 : Event
{
}
public class Event2 : Event
{
}
Publisher project
Publishers EndpointConfig
namespace SemplePublisherNamespace
{
using NServiceBus;
public class EndpointConfig : IConfigureThisEndpoint, AsA_Publisher
{
}
}
Publishers OnBusStart class
public class OnBusStart : IWantToRunWhenBusStartsAndStops
{
public IBus Bus { get; set; }
void IWantToRunWhenBusStartsAndStops.Start()
{
Bus.Publish(new Event1());
Bus.Publish(new Event2());
}
void IWantToRunWhenBusStartsAndStops.Stop()
{
}
}
Publishers app.config
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<configuration>
<configSections>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
<section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core"/>
</configSections>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/>
<AuditConfig QueueName="audit" />
</configuration>
Subscriber project
Subscribers EndpointConfig
namespace SampleSubscriber
{
using NServiceBus;
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server
{
}
}
Subscribers app.config
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<configuration>
<configSections>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
<section name="AuditConfig" type="NServiceBus.Config.AuditConfig, NServiceBus.Core" />
</configSections>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error" />
<UnicastBusConfig>
<MessageEndpointMappings>
<add Assembly="Messages" Endpoint="SemplePublisherNamespace" />
</MessageEndpointMappings>
</UnicastBusConfig>
<AuditConfig QueueName="audit" />
</configuration>
Note that in MessageEndpointMappings secion when adding mapping we set Endpoint name and it's the same as namespace of EndpontConfig class in Publisher project.
Subscriber's Handler class
public class Subscriber : IHandleMessages<Event>
{
public void Handle(Event message)
{
Console.WriteLine("Handle: "+message.GetType().Name);
}
}
Another possible approach would be to have your Event acting as a generic envelope with the actual content inside:
public class GenericEnvelope
{
...
public XmlElement Message { get; set; }
}
This still lets you subscribe once and then pass whatever the content you want but the advantage of such approach is that the envelope could possibly contain some message-oriented attributes that are not part of the message. Another advantage is that passing the content as XmlElement lets you implement your own message-level security/integrity (signing and/or encryption).

NServiceBus Distributor in only 2 steps?

Im having a bit of trouble figuring out how to do the following correctly with the Distributor:
Create a service (distributor) which sends commands, that are distributed among workers. If I start a Distributor with IWantToRunAtStartup implementation I can achieve this behaviour. See below.
Create a service (worker) which handles these commands. This worker I would then start X number of instances of to scale out.
This is all on the same machine so far.
The samples which are included with NSB are a bit hard to understand or maybe its just me :).
Example, I have a distributor and a worker:
Distributor:
class MessageCreator: IWantToRunAtStartup
{
public IBus Bus { get; set; }
public void Run()
{
Thread.Sleep(5000); //Allow workers to checkin
for (int i = 0; i < 1000; i++ )
{
Bus.Send(new DoWorkForCustomerCommand { CustomerID = i });
}
}
public void Stop() { }
}
...
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server
{
public void Init()
{
Configure.Instance.RunDistributor();
}
}
app.config
<configSections>
<section name="Logging" type="NServiceBus.Config.Logging, NServiceBus.Core" />
<section name="UnicastBusConfig" type="NServiceBus.Config.UnicastBusConfig, NServiceBus.Core" />
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
</configSections>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error"/>
<Logging Threshold="INFO" />
<UnicastBusConfig>
<MessageEndpointMappings>
<add Messages="Messages" Endpoint="Worker" />
</MessageEndpointMappings>
</UnicastBusConfig>
Worker:
public class MessageHandler: IHandleMessages<DoWorkForCustomerCommand >
{
public void Handle(DoWorkForCustomerCommand message)
{
Console.WriteLine("Handled customer with Id: " + message.CustomerID );
}
}
...
public class EndpointConfig : IConfigureThisEndpoint, AsA_Publisher
{
public void Init()
{
Configure.Instance.EnlistWithDistributor();
// For some reason this: Configure.Instance.RunDistributor(); achieves the same thing.
}
}
app.config
<configSections>
<section name="MessageForwardingInCaseOfFaultConfig" type="NServiceBus.Config.MessageForwardingInCaseOfFaultConfig, NServiceBus.Core" />
</configSections>
<MessageForwardingInCaseOfFaultConfig ErrorQueue="error" />
This works on my machine and distributes nicely to any number of workers I start, but am i not missing out on something, the ScaleOut example seems more complex?
And why can i start the worker as a distributor and then see the worker act as if it was a worker when in fact is was started as a distributor?
Will this not work across machines if I just add a queue name/endpoint in the worker app.config?
By default if you RunDistributor(), then NSB will run a Distributor with a Worker node in the same process. This is why you see a Worker despite the RunDistributor() configuration. To disable this, use RunDistributorWithNoWorkerOnItsEndpoint() instead. All of this will work across machines by changing the config.
I might suggest using the Profiles instead as this simplifies the config a bit. You can use the NServiceBus.Distributor and NServicerBus.Worker profiles. The profiles will give you more diagnostic information if you have not configured things quite right. Hope this helps.

How to write error log or exception into file in C#.NET

I need help in writing error into separate text file and Email that file to me. Actually, I had created windows application but I didn't add any exception or writing error into separate file. Now, I want whenever my application is interrupted because of any error then error should be noted into separate text file and that file should be email to me.
I did research on error log file and all I found that create separate Class for writing Error Log into text file and call that file into try-catch block of all the methods. But my program/application has grown vast and I need to add intermediate of it. Also, I found about log4net but still it works in same manner.
Can anyone guide me how to write error log at application level or when application get any error message?
Thanks for help.
As far as I can see, all you need is to handle AppDomain.UnhandledException Event. It will give you most common information about crash. You can use it to start the research of crash reasons.
And of course in the UnhandledException handler you can use whatever you want, log4net or custom logger.
If you are not attached to any system already, I'd suggest you look at log4net, since it will do what you're asking for, way, way, more, and is a popular library so it will be recognizable and extensible by other professionals on your team. Also since someone else maintains it you will occasionally get free bug fixes.
try
Log4Net
Smtp Logger:
<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
<to value="to#domain.com" />
<from value="from#domain.com" />
<subject value="test logging message" />
<smtpHost value="SMTPServer.domain.com" />
<bufferSize value="512" />
<lossy value="true" />
<evaluator type="log4net.Core.LevelEvaluator">
<threshold value="WARN"/>
</evaluator>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%newline%newline" />
</layout>
To handle all exceptions anywhere that are not caught elsewhere, consider implementing handlers for Application.ThreadException
I created a logging helper that I use for my WPF project. This is a large project with many different components. This was before I learned how to work with MVVM so please excuse if this breaks the pattern. This system is continuously expanding with new components to handle different tasks. You can think of a component as a standalone unit which handles a specific task, with the Main Component being the master of them all. This logging allowed us to log errors no matter in which component they occurred. It may be an overkill, but worked very well for us.
I am using the same principle to log all system wide events (User Actions, Data Changes..etc)
In my App.xaml.cs I catch all unhandled errors. Note that this is last resort of logging, I use try catch wherever I would expect exceptions to occur (db connections for example).
public partial class App : Application
{
void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
ErrorEvent errorEvent = new ErrorEvent();
errorEvent.LogErrorEvent(e.Exception);
e.Handled = true;
}
}
ErrorEvent is a class within my Utilities dll that uses Event Routing to log the errors. I have different type of errors, depending on severity. All these errors are logged into a database, and the only component aware of the database connections is the main one. This is why I use Routing Event to send the exception to the Main Component to be logged. The ErrorEventHelper gets populated and routed to the Main Component. In situations where I am using try catches, I create the EventHelper and pass it to be logged using LogErrorEvent method. The ShowMessage property is used to decide if the user will be inform of the exception, or if it will only be logged.
public class ErrorEvent : UserControl
{
public delegate void ErrorEventEventHandler(object sender, RoutedCustomEventArgs e);
public static readonly RoutedEvent EventOccuredEvent = EventManager.RegisterRoutedEvent(
"EventOccured", RoutingStrategy.Bubble, typeof(ErrorEventEventHandler), typeof(ErrorEvent));
// Provide CLR accessors for the event
public event RoutedEventHandler EventOccured
{
add { AddHandler(EventOccuredEvent, value); }
remove { RemoveHandler(EventOccuredEvent, value); }
}
public void LogErrorEvent(ErrorEventHelper occuredEventDetails)
{
RoutedEventArgs newEventArgs = new RoutedCustomEventArgs(ErrorEvent.EventOccuredEvent, occuredEventDetails);
RaiseEvent(newEventArgs);
}
public void LogErrorEvent(Exception exception)
{
ErrorEventHelper occuredEventDetails = new ErrorEventHelper();
occuredEventDetails.ErrorType = ErrorEventHelper.EventTypes.Critical;
occuredEventDetails.ErrorValue = exception.Message;
occuredEventDetails.ErrorStack = exception.StackTrace;
occuredEventDetails.ShowMessage = true;
RoutedEventArgs newEventArgs = new RoutedCustomEventArgs(ErrorEvent.EventOccuredEvent, occuredEventDetails);
RaiseEvent(newEventArgs);
if (exception.InnerException != null)
{
LogErrorEvent(exception.InnerException);
}
}
public class RoutedCustomEventArgs : RoutedEventArgs
{
public ErrorEventHelper OccuredEventDetails { get; private set; }
public RoutedCustomEventArgs(RoutedEvent routedEvent, ErrorEventHelper occuredEventDetails)
: base(routedEvent)
{
this.OccuredEventDetails = occuredEventDetails;
}
}
}
public class ErrorEventHelper
{
public string ErrorValue { get; set; }
private EventTypes _ErrorType = EventTypes.Critical;
public EventTypes ErrorType
{
get
{
return _ErrorType;
}
set
{
_ErrorType = value;
}
}
public string ErrorStack { get; set; }
public bool ShowMessage { get; set; }
public enum EventTypes
{
Critical,
Warning,
Information
}
public void SendMessage()
{
ErrorEvent newEvent = new ErrorEvent();
newEvent.LogErrorEvent(this);
}
}
In the MainWindow I register the event handler.
EventManager.RegisterClassHandler(typeof(ErrorEvent),
ErrorEvent.EventOccuredEvent, new ErrorEvent.ErrorEventEventHandler(LogOccuredErrors));
And finally handle it:
private void LogOccuredErrors(object sender, ErrorEvent.RoutedCustomEventArgs e)
{
ErrorEventHelper eventHelper = e.OccuredEventDetails;
//Call Database Helper to log to database or output to file and email
StringBuilder builder = new StringBuilder();
builder.AppendLine(eventHelper.ErrorType);
builder.AppendLine(eventHelper.ErrorValue);
builder.AppendLine(eventHelper.ErrorStack);
if (eventHelper.ShowMessage)
{
MessageBox.Show(eventHelper.ErrorValue);
}
//Create your log file and email it
File.WriteAllText(#"C:\log.txt", ControllerBuilder.ToString())
//email here
}

Add a element in a non static object from a static method?

I know how to use nlog to log my information in a file but now I would like to redirect my log to a ListView (C#) and do some actions. So I directed my log to a method as explained in the documentation nlog. It works.
<?xml version="1.0" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="msgbox" xsi:type="MethodCall" className="SomeNamespace.MyClass, MyAssembly" methodName="LogMethod">
<parameter layout="${level}" />
<parameter layout="${message}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Debug" writeTo="msgbox" />
</rules>
</nlog>
Console.WriteLine works. It's not my problem.
namespace SomeNamespace
{
using System;
public class MyClass
{
public static void LogMethod(string level, string message)
{
Console.WriteLine("l: {0} m: {1}", level, message);
// logListView.Items.Add(Message);
// Do some other actions
}
}
}
I would like to add a line to my logListView (see commented line) but I can't because logListView is not static. How so? How do I proceed ?
One solution would be to add a static member to MyClass, like this:
public class MyClass
{
public static ListView MyListView { get; set; }
public static void LogMethod(string level, string message)
{
Console.WriteLine("l: {0} m: {1}", level, message);
var logListView = MyListView;
if (logListView != null) {
logListView.Items.Add(Message);
}
// Do some other actions
}
}
You can set the value of MyListView from some other part of your application when it is available.
While this solution would work, I would not prefer it because it is counter-intuitive. What you are doing here is declaring in static configuration a log target that is not meaningful at all in a static context: you want to log to a UI control that has not been created, there is no good way to refer to it until the application's UI has been shown, and the UI will be shown at some point or (academically speaking) maybe not at all.
I believe it is preferable to create your own log target class deriving from Target or TargetWithLayout. You can pass any parameters necessary (e.g. the ListView instance) to the log target's constructor, and add the log target programmatically at the point where the values of these parameters become known (i.e. the UI is shown and we have a ListView we can refer to).

Categories