14. Advanced topics: OSGi registration Best practice for registering FFDC extensions (formatters, data collectors, providers, incident forwarders) in OSGi is to use declarative services. Here is an example: Add to the MANIFEST.MF the line: Service-Component: OSGI-INF/CustomerFormatter.xml and add the OSGI-INF/CustomerFormatter.xml file with the content: <? xml version = "1.0" ?> < scr:component xmlns:scr = "http://www.osgi.org/xmlns/scr/v1.1.0" immediate = "true" name = "CustomerFormatter" > < implementation class = "howto_ffdc.domain.ffdcsupport.CustomerFormatter" /> < service > < provide interface = "com.ibm.ffdc.config.Formatter" /> </ service > </ scr:component >
15.
16.
17.
Editor's Notes
We’re here today to discuss First Failure Data Capture (FFDC) which is a serviceability component that complements log and trace in understanding root cause of problems while a system is running.
The agenda for today starts with a description of FFDC, an explanation of some of the key concepts necessary to fully exploit FFDC, then we start into samples that show FFDC usage.
FFDC is used only when problems occur in java code What differentiates it from logging is that: An exception has already occurred. This means that performance has been impacted and the code is in a failure path FFDC is in the category of dump or snapshot type tools. These tools aim to provide a broad view of the system at a particular point in time. Logging keeps a narrow view, over a period of time Each FFDC statement executes only once (some rare caveats we discuss later). If the statement is executed again, it will know that it has already been executed, and it will simply update summary information. This means that FFDC processing can focus more on capturing all needed information, and less on performance. The FFDC infrastructure provides many points where developers can plug in code that will be called when appropriate. The class or method experiencing a failure rarely knows all of the needed context to resolve the problem. FFDC provides extensions so that more focused serviceability code can take a more holistic view and gather a much broader context. The extension points can be used in OSGi or J2SE environments. FFDC is used in WebSphere, but it is not dependent on WebSphere. Its only dependency is JDK 1.5 or later. FFDC keeps a running tab on all FFDC incidents that occur. When a particular incident occurs multiple times, it is only processed the first time. Subsequent calls simply update the summary information. A reference in the back refers to a CAPS (Council for Advanced cross Product Serviceability) web site discussing FFDC best practices and concepts further
As you’ll see from the samples, FFDC is simple to use. While it provides tremendous functionality and extensibility, simple usage requires little more than including one jar in a class path and making calls that closely resemble logging calls When an FFDC log call executes, if it is the first time, it generates an incident and updates a summary. Depending on configuration, each incident can be a separate file in a directory, or the incidents and summary information can be appended into a single file or outputStream FFDC provides logging-like guards which can be used to avoid the cost of gathering information if that process is expensive One of the most powerful extension points in FFDC is the Data Collector. This is a class provided by the caller that will be called if the callStack in the exception includes certain classes or methods. An example of this is that a caller can provide a Data Collector that capture all key information about the WebContainer, and register this Data Collector to run if the callStack includes WebContainer classes. Basically, a Data Collector has relevant domain knowledge that the caller of FFDC need not have. Formatters are another important FFDC extension point. FFDC can use java reflection to render all of the context objects passed in as well as their child objects down to 3 levels (grand-children). In some cases, however, a custom formatting of an object greatly improves the usability of its rendering. This extension allows callers to create classes that do custom formatting. IncidentForwarders are 3 rd of 4 current extensions. This enables a caller to be informed any time an FFDC incident is created. This enables the caller to provide auxiliary function. An example is the FFDC Analyst project which will forward incidents to a Prosol data base where problem reDiscovery will occur based on advanced heuristics which compare callStack qualities. The final extension point is a provider. This is also for advanced users only. It enables custom handling of FFDC incidents for callers who have additional functionality requirements and/or legacy compatibility issues FFDC maintains a table in memory (also dumped periodically to a file or output stream) with all the incidents that have occurred along with additional properties about the incident (how many times has the log call been executed, when was the last time, where did the original incident get written). It’s important to note here that, even though FFDC provides highly extensible and powerful functionality, very little is required to get started and to greatly improve your software serviceability. The added functionality, if needed, is something your software can grow into.
This is an example of using FFDC. When an exception is caught, a call to Ffdc.log is made. The arguments are described there: The Exception. This is a java exception which provides much of the information that FFDC needs to function The reporting class. This is important to the FFDC processing and becomes the first object rendered The sourceId. This is part of the key that makes an incident unique. Most callers use the className and methodName concatenated together The ProbeId. This is a second part of the key. Most callers either use a line number, or some indication to uniquely identify this log call The rest is a list of context data elements. These are objects whose information will be valuable in understanding exactly what went wrong. It is generally best to err on the side of sending too much.
This slide shows how FFDC handles the log call from the last slide First it checks to see if this log statement has occurred before. It compares the “incident key” (which is made up of the “sourceId”, “probeId”, and exception name) against the summary table to see if this incident has already occurred. If it has already occurred, then FFDC updates the summary table and returns to the caller (no new incident is created) FFDC then goes through the call stack and compares each stack frame to see if any Data Collectors are listening for that package/class/method combination. Remember data collectors are a mechanism callers can use to gather additional context data. They register to be called if certain classes are in the call stack. So if there is a match between a class in the call stack and a class that a data collector has registered to listen to, then the data collector will be called, and it will return additional context data we call captured data elements (CDEs) FFDC creates an incidentStream and writes key information from the call and the exception into the incidentStream Now that all “captured data elements” (those from the log call and those from the Data Collectors) are there, FFDC begins to render all of the information into the incident stream. For each cde, it first checks to see if there is a registered formatter to do custom formatting. If not, it checks to see if the cde is formattable (if it implements the formattable interface). If not, the cde is rendered via java reflection. If there is sensitive data in the object that should not be rendered, it is not required to do custom formatting. Placing the annotation @FFDC_OMIT above an object will tell FFDC not to render the information even if using reflection Incident is finally rendered to the output location (separate file or append to running file or outputStream) and the summary table is updated The summary report is updated to reflect addition of this incident If there are any registered incidentForwarders, they will be notified of the incident
This is a graphical depiction of the flow from the previous slide. It focuses on what is built into the infrastructure and what is provided by the caller. Remember that everything but the Log call itself is a customization that is not needed to get started. These are there to help provide better context and customized behavior without having the primary code in your software focus on detailed context collection.
This is a typical example in code. This is an excerpt, the full compilable and runnable samples are referenced in the Resources section at the end of the presentation. Import of Manager.Ffdc is the only required FFDC import. Other imports are needed only if exploiting more advanced FFDC functions System Property com.ibm.ffdc.log determines which default FFDC Provider is used. Providers determine the behavior of FFDC and the handling of incidents. Several providers are provided with FFDC and developers can implement the provider interface and create their own back end behavior. The code using FFDC need not be concerned with which provider is in place Providers can be changed at a later time by the application using FFDC The values for the default (startup) provider are: <fileName> if a file name is specified, the logic is as follows: If it exists and it is a file, a file of that name is created and all incidents and summary reporting are appended into that file If it exists and is a directory, then all incidents are written as separate files into that directory. The summary report will also be a separate file in that directory If it does not exist and com.ibm.ffdc.log ends in File.separator (\\ or /) a directory is created and all incidents are written as separate files into that directory. The summary report will also be a separate file in that directory If it does not exist and com.ibm.ffdc.log does not end in File.separator (\\ or /) a file of that name is created and all incidents and summary reporting are appended into that file Output Stream options System.out or System.err append the incidents and summary report to the stdout or stderr output stream (System.err is the default) A final option of Suppress is available which will discard all ffdc information In the caller’s code, you see that the Ffdc.log appears in the catch block, when an exception has been generated You can see the option to call Ffdc.log directly as is done here, or to create the ffdc object and use the isLoggable trace guard. The trace guard option is for when it will be expensive to gather the needed cdes for the call Log statement can have an arbitraty number of objects at the end. If collections or arrays are passed explicitly, they will be rendered completely. Every element will show up in the incident If arrays or collections are discovered in rendering other objects, just the properties of the collection or array will be rendered (number of elements and type)
This is an example of using a Formatter. Note the extra import statements for the registration process and the trace guard. This shows J2SE programmatic registration, OSGi enables declarative and programmatic registration You can see the 2 lines that construct and register the formatter. This can be done anywhere and any time. It will take affect immediately. The code doing FFDC logging need not be aware of registered formatters When the FFDC infrastructure renders the customer object, it will find this registered formatter and drive it
This is the actual formatter referenced on the previous slide. Note that it is passed a reference to the object and the IncidentStream being used to render the object. Formatter must have access to the information in the object. Examples would be public/protected members, getr methods, or reflection The formatTo method uses write methods on the incident stream to pass the information from the object back to the FFDC infrastructure The getSupportedTypeNames method returns an array of package.class names that this formatter can format. Class can be a regular expression, package cannot The isSupported method takes a Class and determines if this formatter will work on it.
This is a sample using a Data Collector. Note that the registration of the data collector is similar to registering a formatter. Note here, that it would be easiest to pass exposedGlobals on the log call, but we are getting it via the Data Collector to demonstrate data collector functionality Remember, a DataCollector is a specialist in collecting data from a particular piece of the environment. The caller need not know about that part of the environment or that a Data Collector is even registered.
This is the data collector used on the prior slide Unlike a Formatter which uses IncidentStream write methods, the Data Collector returns its information as a Collection which FFDC sees as Captured Data Elements or CDEs. The getSupportedTypeNames provides a list of package qualified class names, and optionally a method with each. If any of these classes are seen in the callStack of the exception, then this data collector will be called. If this data collector matches multiple entries in the callStack, it will only be called once. Data Collector must have a mechanism for accessing the data it needs. Advanced exploiters of FFDC have used singleton global classes to give the DataCollectors starting points to gather the information needed. In the WebSphere space, a Data Collector can use MBeans, HealthCheckers, Diagnostic Providers, or any other mechanism that exposes data
When FFDC renders an object, it first determines if the caller has any custom formatting. Registered formatters are the first option, then Formattable, and finally reflection Note that each original context data element in the Ffdc.log call are rendered down to 3 levels of children. As each child, grandChild, or greatGrandchild object is rendered, it uses the same formatting hierarchy. An example: If a connection pool uses Ffdc.log and sends a collection of connections … each connection may be rendered by a registered Formatter This connection may include a connectionStatus child that the Formatter writes back to FFDC. This connectionStatus is Formattable. FFDC will find it implements Formattable and drive its formatTo object The connectionStatus child object may include a date in it that is rendered via reflection
FFDC exploits, but does not require OSGi. While our prior examples showed registration in a J2SE environment, the next 2 slides demonstrate registration in an OSGi environment. In an OSGi envioronment, declarative registration is a simple approach. In our sample, an entry is made in the MANIFEST.MF pointing to a separate XML file The contents of that XML file define the class that will get registered (as the formatter in this case)
Another option for registering extensions in OSGi is programmatic registration of a service. This is generally done in the Activator class of a bundle using the start method The process is to construct your class, then register it as a service
The registration process of extending FFDC is completely dynamic. At any time during the life of process; data collectors, formatters, providers, and incident forwarders can be registered or unregistered This is a nice feature but … if an incident has already occurred, then it will not normally occur again until the process stops and restarts To resolve this situation, FFDC enables unblocking of incidents, a specified incident, or all incidents. Unblocking an incident allows the associated FFDC call to render an incident on the next execution. That is, it allows the same incident to occur a second time. This is especially helpful for longRunning processes.