locked
Event Logging with custom event viewer RRS feed

  • Question

  • Hello,

    We are using MCS services and found that we can use custom event viewer name to log "Event Source" name. As we are using two services e.g. Service 1 and Service 2.

    Requirement is to log event error with service definition, e.g. EventSourceName_Service1 and EventSourceName_Service2

    Is it possible to achieve this using MCS services?

    Regards

    Friday, June 11, 2010 12:57 PM

All replies

  • I had suggested a possible way to do this in an earlier post; but here is a better way.  Following this way, you will use ConfigWeb to create a new host-based configuration key (setting); this will be called "EVENT_LOG_NAME" and will be a string.  You create config keys using ConfigWeb; the Configuration Service tutorial has a section on how to do, but here since you are changing a host-level setting:

    1)  Open up the Settings class for your service.  Optionally, you can open up the abstract base class Settings.cs found in the Configuration Service solution, ServiceConfigurationBase project.  If you modify the base class, the advantage is every project you create moving forward will inherit the new setting.  If you modify the base class, then do not modify your host's Settings class as the setting will be inherited. Add a new static member just below the line defining the Event Log source name, as follows (note if you are modifying just for your hosts Settings class, and not the abstract base class, then you will not see the first setting below becuase it is inherited):

    //Reset on app startup from configuration database to Event Log Source name defined in configuration database for an app/service.
    public static string EVENT_LOG = ConfigSettings.EVENT_LOG;
    public static string EVENT_LOG = "";

    2)  Recompile the COnfiguration Service Project to make sure ok.

    3)  In the Configuration Service solution, open up ServiceConfigurtionUtility project, Utility.cs class.  All event logging is performed by a single method here "LogMessage" that looks as follows:

     

     

    /// <summary>Writes to event log. </summary>

     

     

    /// <param name="message">String with message to display/log.</param>

     

     

    /// <param name="messageType">Event Log entry type code</param>

     

     

    /// <param name="logEntry">Whether to log entry. Entry will be logged if configuration database is set for detailed logging and this parameter is true</param>

     

     

    /// <param name="settingsInstance">Instance of the Settings class for the service host. Used to determine if detailed logging is on and Event Log Source name.</param>

     

     

    public static void LogMessage(string message, EventLogEntryType messageType, bool logEntry, object settingsInstance)
    {
    if (!logEntry)
    return;
    string EVENT_LOG = "";
    try
    {
    EVENT_LOG = (
    string)reflectGetField(settingsInstance, "EVENT_LOG");
    EventLog EventLog1 = new EventLog();
    EventLog1.Source = EVENT_LOG;
    EventLog1.WriteEntry(message, messageType);
    }

     

     

    catch (Exception e)
    {
    //Choice here: sometimes Web apps will throw a security exception
    //writing to the event log if the source is not setup properly and the account 'Network Service'
    //given "Full Control" to the event log to be able to write entries. Really, this exception should
    //be thrown so user knows they are not getting event log info; however, to avoid frustration
    //for those that get it, I am simply trapping here. Otherwise, you may wish to uncomment this line:
    //

     

     

    // throw new Exception("An exception occurred attempting to write to the Windows Application Event Log. Please make sure the 'Network Service' account (the account ASP.NET runs under) has write access to the Application Event Log. You will use RegEdit to add permissions, refer to the StockTrader Readme.html for precise instructions.\nThe specific exception writing to the " + EVENT_LOG + " Application Log event source is: " + e.ToString());
    //

     

     

    //So if you catch an exception here, check e to see if a security exception. If so, likely need to add Network

     

     

    //Service to EventLog permissions via regedit, current control set, services, Event Log (select), then

     

     

    //from main menu choose Permissions to add Network Service with Full Control (so ASP.NET/IIS can create/and write to).

     

     

    string throwaway = e.Message;
    }
    }

    4)  Change this method to look instead as follows:

     

     

    public static void LogMessage(string message, EventLogEntryType messageType, bool logEntry, object settingsInstance)

    {

     

     

    if (!logEntry)

     

     

    return;

     

     

    string EVENT_LOG = "";

     

     

    string EVENT_LOG_NAME = "";

     

     

    try

    {

    EVENT_LOG = (

     

    string)reflectGetField(settingsInstance, "EVENT_LOG");

    EVENT_LOG_NAME = (

     

    string)reflectGetField(settingsInstance, "EVENT_LOG_NAME");

     

     

    if (EVENT_LOG_NAME == "")

    EVENT_LOG_NAME =

     

    "Application";

     

     

    EventLog EventLog1 = new EventLog(EVENT_LOG_NAME);

    EventLog1.Source = EVENT_LOG;

    EventLog1.WriteEntry(message, messageType);

    }

     

     

    catch (Exception e)

    {

     

     

    //Choice here: sometimes Web apps will throw a security exception

     

     

    //writing to the event log if the source is not setup properly and the account 'Network Service'

     

     

    //given "Full Control" to the event log to be able to write entries. Really, this exception should

     

     

    //be thrown so user knows they are not getting event log info; however, to avoid frustration

     

     

    //for those that get it, I am simply trapping here. Otherwise, you may wish to uncomment this line:

     

     

    //

     

     

    // throw new Exception("An exception occurred attempting to write to the Windows Application Event Log. Please make sure the 'Network Service' account (the account ASP.NET runs under) has write access to the Application Event Log. You will use RegEdit to add permissions, refer to the StockTrader Readme.html for precise instructions.\nThe specific exception writing to the " + EVENT_LOG + " Application Log event source is: " + e.ToString());

     

     

    //

     

     

    //So if you catch an exception here, check e to see if a security exception. If so, likely need to add Network

     

     

    //Service to EventLog permissions via regedit, current control set, services, Event Log (select), then

     

     

    //from main menu choose Permissions to add Network Service with Full Control (so ASP.NET/IIS can create/and write to).

     

     

    string throwaway = e.Message;

    }

    }

     

     5)  Recompile Configuration Service Solution; then also recompile your own host service solution picking up all the new shared libraries for Config Service.

    6)  Login to ConfigWeb for your service.  Choose Edit Configuration at the Host Level (top link--these are the app server-global keys every app gets, not app-specific settings).  You will then add a Key, of type string, with a field name of "EVENT_LOG_NAME".  You can give it a default value of "Application" so until changed, events will be written to the server's Application event log, not a custom source.

    At this point, once added, you should be able to set this to a custom name for your service, so event enrties are written to your custom log instead of always the Application event log.

    -Greg


    Greg Leake, Microsoft
    Thursday, June 17, 2010 6:06 PM
    Moderator
  • Oops, sorry the code came through so chopped up.  The one mistake above, is the added field in step one should be public static string EVENT_LOG_NAME = "";  I accidently typed "EVENT_LOG" which is already defined and equates to the event log source name already.

    -Greg


    Greg Leake, Microsoft
    Thursday, June 17, 2010 6:10 PM
    Moderator
  • And one last note, given my two previous posts:

    You will also need to make sure the Custom Event Log is created on the computer(s) you will be running your services on.  To do this, see:

    http://msdn.microsoft.com/en-us/library/49dwckkz(VS.80).aspx

    Basically, you can create a Console Application that uses the following line of code:

    System.Diagnostics.EventLog.CreateEventSource("EventSourceName", "LogName");
     

     You would need to run this using Administrator rights (on Win 7/Vista, right-click and "Run as Administrator").  Once run, this should pre-create the custom log name on each computer.

     

    -Greg


    Greg Leake, Microsoft
    Thursday, June 17, 2010 6:27 PM
    Moderator
  • Hi greg,

    Thanks very much for detailed information.

    Our requirement is as detailed below,

    1. We have custom event viewer "SODA", which we use to log the errors created using MCS website.

    2. We have Service1 and Service2 hosted using MCS configweb.

    3. When Service1 throws an error, we want the error should get logged inside "SODA" event log with source name "Error_Service1". Same applies to Service2 errors.

    4. "SODA" is the event viewer folder name like "Application", while "Error_Service1" and "Error_Service2" is the source name when the error is logged into event viewer "SODA"

    5. Take a look at following error

    Event Type: Error
    Event Source: SODA_IE_ReportGenerator
    Event Category: None
    Event ID: 5096
    Date:  6/21/2010
    Time:  12:34:16 PM
    User:  N/A
    Computer: TESTMAC
    Description:
    Timestamp: 6/21/2010 12:34:16 PM
    Message:
    POLICY NAME: EventLogger

    We want Event Source to be Error_Service1 and Error_Service2 while both the errors will get logged to custom event viewer "SODA"

    6. We do not want two different custom logs to be created rather we need source name to be appropriate with only one custom log i.e. "SODA"

    regards,

    Monday, June 21, 2010 10:19 AM
  • You can do this but there are two scenarios (both pretty easy):

    1) Case1: You are hosting Service1 and Service2 in two distinct service hosts (each with its own autonomous service config repository/database).  This is the case, for example, if self-hosting, you are using two distinct .exe or NT Service programs each with own unique config database.  Or, if hosting in IIS, using two separte vdirs/apps, each with own seperate config dbs. 

    This is the easier case.  Simply follow the above instructions, but create the new config key EVENT_LOG_NAME for each of the two service hosts (they will be maintained in each respective host's config db separately). Then, using ConfigWeb, set the name of the newly created key EVENT_LOG_NAME to the same value for each service host.  The custom log name for each will be SODA.  Then, for host1/service set the value for EVENT_LOG (which equatest to the event source name for each entry written) to Error_Service1.  Set the EVENT_LOG setting for host2/service2 to Error_Service2.  Remember to pre-create the event log and event sources (see MSDN link above) before deploying to servers.  For any machine hosting one, or both service hosts, all entries should be written to the same custom event log named SODA; however, service1 entries will be written as event source name = Error_Service1; and service entries will be written as event source Error_service2. 

    2) Case2: You are hosting Service1 and Service2 in the same service host (same .exe, NT Service, or IIS vdir/app, with only one service config repository).  Here, still follow the instructions above to create the EVENT_LOG_NAME config setting for the host; and modify the LogMessage method in ConfigUtility Utility.cs file as instructed above.  Give this setting a value of SODA. Now, however, you should create two app-level settings (config keys), one called EVENT_LOG_SERVICE1 and one called EVENT_LOG_SERVICE2.  You can put these in a new app level grouping; two different groups, however you want to appear in config web.  Set EVENT_LOG_SERVICE1 to "Error_Service1"; and EVENT_LOG_SERVICE2 to "Error_Service2".  You will now add an overloaded method definition in ConfigUtility Utility.cs file:
    ------------------------------------

    public static void LogMessage(string message, EventLogEntryType messageType, bool logEntry, object settingsInstance, string EVENT_LOG_SOURCE)

    if (!logEntry)
    return; 
    string EVENT_LOG_NAME = "";
    string EVENT_LOG= "";
    try
    {

    if (EVENT_LOG_SOURCE == null)
       EVENT_LOG = (string)reflectGetField(settingsInstance, "EVENT_LOG");
    else
       EVENT_LOG =
    EVENT_LOG_SOURCE;
    EVENT_LOG_NAME = (string)reflectGetField(settingsInstance, "EVENT_LOG_NAME"); 
    if (EVENT_LOG_NAME == "")
    EVENT_LOG_NAME = "Application"; 
    EventLog EventLog1 = new EventLog(EVENT_LOG_NAME);
    EventLog1.Source = EVENT_LOG;
    EventLog1.WriteEntry(message, messageType);
    }

    catch (Exception e)
    {
       string throwaway = e.Message;
    }
    }

    -----------------------------------------------

    Finally, in your business logic, when you want to write and event log entry (eg exceptions); if exception is in business logic for Service1; you will call overloaded method as follows:
    -------------------------------------
    try
    {
       //Business logic here for Service1 method(s)
    }
    catch (Exception e)
    {
        ConfigUtility.LogMessage("Exception Service1 is: " + e.ToString(),EventLogEntryType.Error,true,  new Settings(), Settings.EVENT_LOG_SERVICE1)
    }
    ---------------------------------------

    For exceptions in your business logic for Service, you will make the following call to the new overloaded method:

    try
    {
       //Business logic here for Service2 method(s)
    }
    catch (Exception e)
    {
        ConfigUtility.LogMessage("Exception Service2 is: " + e.ToString(),EventLogEntryType.Error,true,  new Settings(), Settings.EVENT_LOG_SERVICE2)
    }

    The result should be as desired. 

    Hope this helps,

    Greg

     

     

    {


    Greg Leake, Microsoft
    Monday, June 21, 2010 7:56 PM
    Moderator
  • Hi Greg,

    We tried with Case1 and found following error on the configweb url

    ----------------------------------------------------------------------------------------------------------------------------------

    An exception was encountered during the request. The exception was: System.ServiceModel.FaultException: The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs. Server stack trace: at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter) at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at ConfigService.ServiceConfigurationContract.IServiceConfiguration.receiveConfigurationKey(String targetHostNameIdentifier, String targetConfigServiceNameIdentifier, ConfigurationKeyValues oldKey, ConfigurationKeyValues newKey, Boolean notifyNodes, String action, List`1 traversePath, ServiceUsers csUser) at ConfigService.ServiceConfigurationRemote.ServiceConfigurationClient.receiveConfigurationKey(String targetHostNameIdentifier, String targetConfigServiceNameIdentifier, ConfigurationKeyValues oldKey, ConfigurationKeyValues newKey, Boolean notifyNodes, String action, List`1 traversePath, ServiceUsers csUser) in C:\stockrtm\Configuration\ServiceConfigurationClient\ServiceConfigurationClient.cs:line 417 at ConfigService.ServiceConfiguration.Web.ManageKeys.processUpdate() in c:\stocktrader\Configuration\ConfigManagementWeb\ManageKeys.aspx.cs:line 265

    ------------------------------------------------------------------------------------------------------------------------------------

    we tried adding new key using Manage Configuration Key page and found the above error.

    Regards

     

    Wednesday, June 23, 2010 11:32 AM
  • Hmm...I will look into but need more info.  The above is just the client-side error.  I need the exception from the service itself; For this, you need to look in the event log of the server, for that machine's event source at the service, in the Application log.  It should be a red icon, with full exception in the event log item detail.

     

    -Greg


    Greg Leake, Microsoft
    Wednesday, June 23, 2010 4:09 PM
    Moderator
  • I have this working.  The trickiest part for me was ensuring the new Event Log and the new Event Log Sources were installed/registered on the host machine(s). 

     

    1) First, I created the following console program to create the Event Log 'SODA'on the local machine, and create two Event Sources, 'Error_Service1' and 'Error_Service2' within this custom event log.  Make sure to run this 'As Administrator' or within a Visual Studio instance launched 'As Administrator':

    using

     

     

    System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    ///First, delete any event source pre-registered for Error_Service1. Assumes
    //failure is event
    source does not exist on local machine.

     

     

    try
    {
    System.Diagnostics.
    EventLog.DeleteEventSource("Error_Service1",".");
    }
    catch {Exception e; }
    ///Next, delete any event source pre-registered for Error_Service2. Assumes
    //failure is event
    source does not exist on local machine.

     

     

    try
    {
    System.Diagnostics.
    EventLog.DeleteEventSource("Error_Service2",".");
    }
    catch { Exception e; }

     

     

    ///Next, attempt delete of any existing local custom log named SODA. Assumes
    //failure is that log
    does not exist/already deleted on local machine.

     

     

    try
    {
    System.Diagnostics.
    EventLog.Delete("SODA",".");
    }
    catch {Exception e; }

    ///Now, create both event sources within the custom Event Log SODA.  The SODA
    //custom event log itself will also be created if does not yet exist.

     

    System.Diagnostics.

     

    EventLog.CreateEventSource("Error_Service1", "SODA");
    System.Diagnostics.
    EventLog.CreateEventSource("Error_Service2", "SODA");

    }
    }
    }

    2. In testing this, I found that if having trouble, you can run RegEdit and find HKEY_LOCAL_MACHINE-->SYSTEM-->ControlSet001-->services-->eventLog and here find any Custom Log (such as SODA) and either delete the entire SODA folder or any subkeys which should be 'Error_Service1' and 'Error_Service2' to start from scratch.  Reboot if you do this.  After reboot, run the console application above as Administrator (right-click on .exe, 'Run As Administrator'). 

    At this point, on your server you should now have the proper custom event log SODA created, with two event sources registered and ready as 'Error_Service1' and 'Error_Service2'.  I would reboot the server at this point anyway, right after successful run of the console app above.

    3) Next, make sure you have modified your ConfigUtility Utility.cs LogMessage method per the posts above. 

    4) Also in the Configuration Solution, modify the ServiceConfigurationBase (project) Settings.cs abstract base class to include the new setting
    public static string EVENT_LOG_NAME = "";  I put this definition right under the existing definition for EVENT_LOG.  EVENT_LOG will be your source (eg 'Error_Service1' or 'Error_Service2'; The new EVENT_LOG_NAME will be the custom event log, in this case 'SODA' after completing steps below.

    5) Recompile the Configuration Solution.  Recompile your solutions for your two custom apps that implement the Configuration Service so they both pick up the new Configuration Service shared libraries.

    6)  Login via ConfigWeb to your first host (either IIS-hosted or self-hosted, does not matter).  At first top-level 'Edit Configuration' link (these are the app-wide inherited settings) click on link.  Choose 'Define/Edit Keys'.  Choose 'Add Key.'

    7)  Enter following values:

    Config Key Display Name:  Custom Event Log Name
    Settings Class Field Name:  EVENT_LOG_NAME
    Settings Group Name:  [leave at the default selected value]
    Data Type:  string
    Key Description: Name of the Custom Event Log to write event entries to
    Key Valid Values:  Any string
    Key Level: Basic (radio button selection)
    Read Only: false (radio button selection)
    Initial Key Value:  SODA
    Display Order: 1

    Click Add.  You should not get an exception unless this key already exists as defined in your service repository. If already exists; you can choose 'Define/Edit' Keys and either edit this existing entry to above values, or delete the key and start from scratch.  Remember the key may already exist as either a host-level setting or in a custom group; so if you do get an error, make sure you search through all settings to see if this EVENT_LOG_NAME key already exists before adding per above.

    8)  Go back to main page in ConfigWeb.  Again choose top-level 'Edit Configuration' link.  Find the entry for 'EventLog' and make sure its set to 'Error_Service1'.  Update value if necesssary.  Your entry for the new key 'Custom Event Log Name' is already set to SODA after completing step 7 above.

    9)  Repeat Step 7 and Step 8 for your second host program.  Except in step 8, give the 'EventLog' entry a value of 'Error_Service2'. 

    10) You should now find in EventVwr.exe (Windows Event viewer) under the 'Applications and Services Logs' folder a new event log named SODA.  Within this, event entries for service host 1 will be under event source Error_Service1 and for service host 2 will be under event Source named Error_Service2.  You will need to make sure to run the console app on every server you will be installing/running the host service programs (in a cluster, any number of machines).

    11) As a side note, it is a bit tricky in that as you change names of these event logs and sources, if an exception is encountered along the way (as happened to you), the server might not write any entry to any log since the log or the source might not exist since you have been changing.  Hence I urge you to start at step 1 above and go through methodically.  I suspect the exception you got might be becuase you have attempted to create the EVENT_LOG_NAME key twice in configweb, which I believe would throw a Duplicate Key exception.

     

    -Greg

     

     


    Greg Leake, Microsoft
    Wednesday, June 23, 2010 7:22 PM
    Moderator