Beautiful Code [249]
204 totalSize += size;
205 return block;
206 }
207 }
208 catch(Exception ex) {
209 close( );
210 throw new MiddlewareException(ex);
211 }
212 }
213 }
Here are some sample streamer service log entries:
Code View: Scroll / Show All
2004-12-21 19:17:43,320 INFO : jqpublic:
Streamer.getDataFile(/surface/tactical/sol/120/jpeg/1P138831013ETH2809P2845L2M1.JPG)
2004-12-21 19:17:43,324 DEBUG: Begin download of file '/surface/tactical/sol/120/
jpeg/1P138831013ETH2809P2845L2M1JPG'
2004-12-21 19:17:44,584 DEBUG: Completed download of file '/surface/tactical/sol/120/
jpeg/1P138831013ETH2809P2845L2M1.JPG': 1876 bytes
Figure 20-6 shows a useful graph of information we can glean from log mining. The graph shows the trend in the amount of downloading (the number of files and the number of bytes downloaded) over a period of several months during the mission. Over shorter periods of time, the graph can show spikes whenever one of the rovers makes an interesting discovery.
Figure 20-6. A graph generated from "mining" the CIP streamer service logs
20.5.2. Monitoring
Logging enables us to analyze the performance of the services by examining what they have been doing over a period of time. Unlike log entries, which are most helpful in pinpointing problems and their causes, runtime monitoring helps us see how well the services are currently performing. It gives us a chance to make dynamic adjustments to improve performance or to head off any potential problems. As mentioned earlier, the ability to monitor operational behavior is often critical to the success of any large application.
The code listings previously shown included statements that update the performance data kept by global static objects referenced by the fields cacheStats and fileStats. A middle-ware monitoring service probes this performance data upon request. The global objects to which these fields refer aren't shown, but you should be able to imagine what they contain. The key point is that it's not complicated to gather useful runtime performance data.
We wrote the CIP Middleware Monitor Utility as a client application that periodically sends requests to the middleware monitoring service to obtain the current performance data. Figure 20-7 shows a screenshot of the utility's Statistics tab that displays, among other runtime statistics, the number of files and bytes that have been downloaded and uploaded by the streamer service, and the number of file errors (such as an invalid filename specified by a client application) that have occurred.
Figure 20-7. Screenshot of the Statistics tab of the Middleware Monitor Utility
The streamer service provider bean's doFileDownload( ) and readDataBlock( ) methods both update the global file error count (lines 50 and 84 in the code shown earlier in the section "Logging"). The getDataFile( ) and readDataBlock( ) methods increment the global total service response time (lines 22 and 94). As seen in Figure 20-7, the middleware monitor utility displays average response times under the "Total Server Response" label.
The file reader bean's getDataFile( ) method records the start of each file download (line 172). The readDataBlock( ) method increments the global total file and byte counts (lines 195 and 196) and records the completion of a download (line 197). Figure 20-8 shows a screenshot of the Files tab of the monitor utility, which displays current and recent file downloading and uploading activity.
Figure 20-8. Screenshot of the Files tab of the Middleware Monitor Utility
A Highly Reliable Enterprise System for NASA's Mars Rover Mission > Robustness
20.6. Robustness
Change is inevitable, and beautiful code can handle change gracefully even after going into operation. We took a couple of measures to ensure that CIP is robust and can deal with changes in operational parameters:
We avoided hardcoding parameters in the middleware services.
We made it possible to make changes to the middleware services that are already in operation with minimal interruption to the client applications.