WOEventSetup page


The page used to set up the logging properties is accessed through a direct action named "WOEventSetup". So for example, WOEventSetup page can be accessed for an application named "MyApp" with a URL such as the following:

http://myhost:aPort/cgi-bin/WebObjects/MyApp.woa/wa/WOEventSetup

On the WOEventSetup page, you can see all families of events that are registered for the application. Since the event classes are registered dynamically as the program executes, it is a good idea to "warm up" an application before accessing WOEventSetup.

The page lists the registered event classes, their subcategories, and a description of the kinds of events that can be logged. For instance, the EOEditingContext event class logs events for the saveChanges and objectsWithFetchSpecification methods. Logging for each class can be enabled and disabled with the corresponding check box; it isn't possible to disable individual subcategories of an event class.

The logging mechanism is extremely fast and memory efficient. A standard 300MHz G3 can log more than 300,000 events per second, so event logging overhead is negligible compared to the time required to generate dynamic web pages.

User Defaults


In addition to the configuration you can do on the WOEventSetup page, the event logging system uses user defaults to additionally configure event logging behavior. The user defaults are:

WOEventDisplay page


The page that displays collected events, WOEventDisplay, is also accessed through a direct action. For example, WOEventSetup page can be accessed for an application named "MyApp" with a URL such as the following:

http://myhost:aPort/cgi bin/WebObjects/MyApp.woa/wa/WOEventDisplay

On this page, events can be viewed in four different ways:

In any of these displays, if an event or event group has subevents, it can be expanded by clicking the hyperlink or triangle image.

Each view orders events by duration (in milliseconds) from the longest to the shortest. Aggregation induces rounding errors, which are a maximum of 1ms per event. In other words, an aggregate event consisting of ten events has at most 1 ms deviation from the actual run time; however, manually adding ten individual events as displayed in the table might have up to a 10 ms deviation. Therefore, any displayed sum is always more accurate than adding up the durations of individual events. Also note that the sub events of an event branch doesn't necessarily add up to the duration of the branch event the branch event's duration might be larger. This because the parent event generally consists of more than just calling the methods causing the sub events.

Custom Event Logging


To define and log custom events, an event class can be created, event's categories and subcategories can be defined, the event class can be registered with the WOEvent center, and you can instrument the portions of code you wants to log. This section describes these steps.

To create a custom event:

  1. Create a subclass of EOEvent or an appropriate subclass.

    For example, to log events for a custom adaptor , say MyAdaptor, create an EOEvent subclass named MyAdaptorEvent. subclass doesn't usually have to override any of the inherited methods, but you can customize the default behavior.

  2. Create a description file for the event and add it to project's Resources folder.

    An event's description file defines the event categories and subcategories used in the WOEventDisplay page. The file's contents is a dictionary in plist format. For the MyAdaptorEvent class, the file's name is MyAdaptorEvent.description , and it might look like the following:

      {
      EOEventGroupName ="MyAdaptor Event ";
      connect ="Connect ";
      openChannel ="Open Channel ";
      evaluateExpression ="Evaluate Expression ";
      fetchRow ="Fetch Row ";
      commitTransaction ="Commit Transaction ";
      }
      
  3. Register the event class with the EOEventCenter.

    Typically you can register an event class in the static constructor of the class whose code you are instrumenting MyAdaptor in this example.

       public static class MyAdaptorEvent extends EOEvent {
    
            protected static final String Connect = "connect";
            protected static final String OpenChannel = "openChannel";
            // etc.
    
            public CustomEvent() {
                super();
            }
    
            public CustomEvent(String type) {
                super();
                setType(type);
            }
        }
    
        public static class MyAdaptorEventLoggingEnabler extends Object implements EOEventCenter.EventRecordingHandler {
            public void setLoggingEnabled(boolean isLogging, Class aClass) {
                _IsEventLoggingEnabled = isLogging;
            }
        }
    
      
      static {
    	EOEventCenter.registerEventClass(MyAdaptorEvent.class, new MyAdaptorEventLoggingEnabler());
      }
      
      

    As in this example, you might want to define string constants for the keys in the event's description dictionary.

  4. Instrument the methods.

    In any method you want to instrument, following code to be added, substituting the appropriate event key. This code instruments the "connect" event of MyAdaptorEvent.

    	EOEvent e = null;
    
      //Setup and start logging
    	if (_IsEventLoggingEnabled) {
    		e = new MyAdaptorEvent(MyAdaptorEvent.OpenChannel);
    		EOEventCenter.markStartOfEvent(e, "openChannel()");
    	}
    
    
      //Code to be timed goes here.
      
      //Finish logging.
    	if (e != null) {
    		EOEventCenter.markEndOfEvent(e);
    	}
    
      

    The second argument to newEventOfClass is an event key corresponding with an entry in the .description file. The corresponding value is used in the Title column of the WOEventDisplay page. If the argument isn't a key in the description dictionary, newEventOfClass uses the argument instead.