Error handling and logging

Similar documents
Kakadu and Java. David Taubman, UNSW June 3, 2003

Lecture 14: Exceptions 10:00 AM, Feb 26, 2018

Exception Handling Alternatives (Part 2)

Starting to Program in C++ (Basics & I/O)

QUIZ Friends class Y;

Program Correctness and Efficiency. Chapter 2

05-01 Discussion Notes

The NetBeans IDE is a big file --- a minimum of around 30 MB. After you have downloaded the file, simply execute the file to install the software.

3. Simple Types, Variables, and Constants

Lambda Correctness and Usability Issues

! Errors can be dealt with at place error occurs

CATCH Me if You Can Doug Hennig

Chapter 1 Getting Started

Chapter 9: Dealing with Errors

11Debugging and Handling. C# Programming: From Problem Analysis to Program Design 2nd Edition. David McDonald, Ph.D. Director of Emerging Technologies

Difference Between Dates Case Study 2002 M. J. Clancy and M. C. Linn

The Dynamic Typing Interlude

Linked lists Tutorial 5b

Object Oriented Programming

CS61C Machine Structures. Lecture 4 C Pointers and Arrays. 1/25/2006 John Wawrzynek. www-inst.eecs.berkeley.edu/~cs61c/

CS 3 Introduction to Software Engineering. 3: Exceptions

Checked and Unchecked Exceptions in Java

Exceptions in Java

Debugging and Handling Exceptions

Unit Testing as Hypothesis Testing

Programming Style and Optimisations - An Overview

Chapter 12 Visual Program Debugger

Outline. Computer programming. Debugging. What is it. Debugging. Hints. Debugging

Week 5, continued. This is CS50. Harvard University. Fall Cheng Gong

EXAMINING THE CODE. 1. Examining the Design and Code 2. Formal Review: 3. Coding Standards and Guidelines: 4. Generic Code Review Checklist:

The Perl Debugger. Avoiding Bugs with Warnings and Strict. Daniel Allen. Abstract

Chapter 3.4: Exceptions

Software Engineering

IS 0020 Program Design and Software Tools

Programming Studio #9 ECE 190

What goes inside when you declare a variable?

CS354 gdb Tutorial Written by Chris Feilbach

The compiler is spewing error messages.

Contents. Slide Set 1. About these slides. Outline of Slide Set 1. Typographical conventions: Italics. Typographical conventions. About these slides

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

OS: An Overview. ICS332 Operating Systems

Lecture Notes on Contracts

BCS THE CHARTERED INSTITUTE FOR IT. BCS Higher Education Qualifications BCS Level 6 Professional Graduate Diploma in IT EXAMINERS' REPORT

Learning Objectives. A Meta Comment. Exercise 1. Contents. From CS61Wiki

DOT NET TRAINING PROGRAM

Sahaj Computer Solutions OOPS WITH C++

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Type Checking and Type Equality

CS Summer 2013

Assoc. Prof. Marenglen Biba. (C) 2010 Pearson Education, Inc. All rights reserved.

Unit Testing as Hypothesis Testing

PROGRAMMING IN VISUAL BASIC WITH MICROSOFT VISUAL STUDIO Course: 10550A; Duration: 5 Days; Instructor-led

LECTURE 0: Introduction and Background

Variables and Constants

Supplement: Visual C++ Debugging

Lesson 13 - Vectors Dynamic Data Storage

Object Oriented Programming Exception Handling

CSE 374 Programming Concepts & Tools

4.2 Variations on a Scheme -- Lazy Evaluation

CS168 Programming Assignment 2: IP over UDP

ApacheCon NA How to Avoid Common Mistakes in OFBiz Development Presented by Adrian Crum

Exceptions. What exceptional things might our programs run in to?

Verification and Validation. Assuring that a software system meets a user s needs. Verification vs Validation. The V & V Process

Cache Coherence Tutorial

So, coming back to this picture where three levels of memory are shown namely cache, primary memory or main memory and back up memory.

Exceptions. Why Exception Handling?

CS 231 Data Structures and Algorithms, Fall 2016

Debugging and Profiling

Chapter 5 Errors. Bjarne Stroustrup

Exception Safe Coding

Memory Addressing, Binary, and Hexadecimal Review

Statistics Case Study 2000 M. J. Clancy and M. C. Linn

CS370 Operating Systems

Object-Oriented Principles and Practice / C++

CSE 303: Concepts and Tools for Software Development

Pointers. A pointer is simply a reference to a variable/object. Compilers automatically generate code to store/retrieve variables from memory

y

Vector and Free Store (Pointers and Memory Allocation)

Enhanced Debugging with Traces

Name: Class: Date: 2. Today, a bug refers to any sort of problem in the design and operation of a program.

Analysis of MS Multiple Excel Vulnerabilities

MICRO DIGITAL: TECHNICAL CRITERIA FOR MAKING THE RTOS CHOICE

COMP322 - Introduction to C++ Lecture 10 - Overloading Operators and Exceptions

Visual Studio.NET. Although it is possible to program.net using only the command OVERVIEW OF VISUAL STUDIO.NET

Summer Cart Synchronization Guide for.net

An Introduction to Komodo

Agenda CS121/IS223. Reminder. Object Declaration, Creation, Assignment. What is Going On? Variables in Java

CS2: Debugging in Java

Introduction to Programming Using Java (98-388)

CS504 4 th Quiz solved by MCS GROUP

Instances and Classes. SOFTWARE ENGINEERING Christopher A. Welty David A. Ferrucci. 24 Summer 1999 intelligence

GDB Tutorial. A Walkthrough with Examples. CMSC Spring Last modified March 22, GDB Tutorial

Data Structure Series

Introduction to Programming in C Department of Computer Science and Engineering. Lecture No. #29 Arrays in C

Testing is a very big and important topic when it comes to software development. Testing has a number of aspects that need to be considered.

Stanford University Computer Science Department CS 295 midterm. May 14, (45 points) (30 points) total

Queens College, CUNY, Department of Computer Science Computational Finance CSCI 365 / 765 Fall 2018 Instructor: Dr. Sateesh Mane

Buffer Overflow Defenses

SmartHeap for Multi-Core

PRODUCT PAGE PHASES and EXPERIENCE DESCRIPTION

Transcription:

Error handling and logging Introduction In my last article in Overload I presented code to facilitate error logging. I d like to stay with this theme and look at some of the issues and concerns involved in logging. When I speak of logging, I normally mean error logging. The actual error logs may be errors, or they may be warnings and information messages. An error log is one end of a spectrum, at the other end is so called trace information which I will also comment on. In addition I ll show how to catch some of NT s more difficult exceptions. Exceptions and libraries C++ provides us with the exceptions mechanism for raising, well, exceptions. An exception is not necessarily and error, it is some situation that occurs in a program which is so unusual as to be an exception. The majority of these cases are errors, i.e. something unusual has happened which is in error. Exceptions provide us with a rich environment to encapsulate and describe the condition that has arisen. All this information can be placed in an object, and the object throw, like a message in a bottle, which, through some angelic determinism 1 will find a suitable handler which can deal with it. This mechanism is most powerful when considered in the light of re-usable code libraries used in multiple projects. If we build a library of classes to represent financial instruments, we may use the library in big server boxes doing calculation for an investment house, or in a workstation product used by floor traders, or even a quick calculator for hand held machines. In each case we will want to handle errors differently. Hence, we must abstract the exception handling mechanism in such a way that the library user makes the decision on what to do when a condition arises. But wait! As developers, who will be called upon to fix the problem, we need to know as much, specific information about how the condition arose to enable us to find and fix the problem typically, the more information we have the quicker we can fix the problem. This is at odds with out wish to abstract the exception. This is where the exception object comes into the picture. When the condition arises the code which detects it should package all the information it can into an object. The object is thrown and when caught a policy decision can be made which determines what happens next. Separate cause and effect The above scenario describes the separation of cause (the exception condition being encountered) and the effect of condition (the functionality failing). This maps conveniently into our developer-user view 1 This expression comes from a lecturer of mine who used it to describe the way a non-deterministic automaton reaches a stop state. I use it here to describe the way a catch will be reached without the thrower being aware of where the catch is in the program.

of the world. As the developer we are concerned with the cause, because we want to fix it. Users, on the other hand, are only concerned with the effect. For example, if during a client-server TCP session the connection is lost and the server query is aborted, the user is only concerned with effect, their query has failed, they do not care why it has failed 2. However, as a developer, I m interested in why was the connection lost, what error number was returned, what was the socket state? And so on. In this scenario, the throw statement is matched with the cause, and the catch statement with the effect. Within the catch block the effects of the condition are felt and action taken. This is where we choose to deal with the condition, it is where the logging should be placed. The code I presented in my previous article could be used as a bed-rock layer upon which libraries can be built. Each library would be able, through this bed-rock to log errors. While this is sometimes what we want, it is better to move the error logging to higher levels where decisions on what action is taken, and what is logged can be taken. Another advantage of separating cause and effect is that we can manage the quantity of information we present. A user does not want to be bothered with a page of statements and a stack unwind, they want a nice simple error message they can report to described what has failed. To us developers a simple one liner like TCP socket failed is next to useless, a several pages of messages and stack unwind are just what we want! ( A nice big red arrow pointing at a bug would be helpful too, but I leave this as an exercise to the reader! ) Tracing Tracing is a form of logging, but it does not deal exclusively with errors. My preferred definition of tracing is: Tracing allows a developer to see inside a program. Most developers are familiar with the idea of adding debug code to a program so they can track what is happening inside during development, but this code is normally removed for release. If we look beyond software development to the semi-conductor industry, or less abstractly, kitchen appliances and car, manufactures increasingly leave debug code in place, and/or provide interfaces through which diagnostics can be exposed. One of my favourite examples are the inspection facilities built into large civil-engineering projects so that bridges, tunnels and building can be inspected once construction has finished. This is where tracing comes in. We should actively seek to leave inspection code in place in a program so that, when in live operation we encounter a problem we have some diagnostic tools to hand. Before I go any further will address the point that many people are already muttering: debug code comes out and allows run-time speed to increase, if we leave in trace code run-times will be hit and footprint increased I won t try and deny this, run-times will be hit but most of the time tracing is switched off, we can engineer our application so the only extra overhead is an occasional if statement. 2 If the user can do something to rectify the problem the situation is slightly different but the program design must be such that allows a user to abort or retry.

When tracing is switched on, performance is hit more but this only happens we have an issue to address. While the run-time overhead argument may of been noticeable back in the days of 6502 and Z80 processors with 64K of RAM, where every cycle and every byte was valued, is the same true in the world of 600Mhz Pentium III s with 128Mb of RAM? Surely, when we specify the machines for our applications we should include capacity for tracing. Few engineering disciplines today would limit service and maintenance opportunities. We accept that a car s engine is accessible through the bonnet, even for those of us who never open it, yet surely the car would be safer is it was welded shut? After all, the garage mechanic can un-weld it when they need to open it! Trace statements can also be viewed as comments. Reading code peppered with trace statements is even better than reading comment code as we can see the comments executing, we can see the actual path through the code, and any doubts we have about the actual execution path are ellayed. And some more things I have not discussed several points that should be considered when designing your exception handling and logging strategy. I hope to cover at least some of them in a future article:? Standard C++ exceptions : we now live in a world with a standard C++ library of exception objects. While these may not be suitable for every project I think we should all plan to use them at the outset of our design. Only abandon them if you find good reason. Some of the common library function will through exceptions of these types so you cannot ignore them altogether. Twelve months ago, this may not of been my advice, but things move on.? Internationalisation : when designing error messages it is worth considering what languages you will need to log errors in. This is particularly important for user facing messages, developer specific information and trace information is probably not worth translating. In reality, I wager, most software, has only one target language 3. Microsoft tackle this problem with a resource file which resides in a separate DLL. While I praise their attempt I believe the Microsoft solution to event logging and internationalisation of log messages is overly complex and lacks any crossplatform merit.? Error codes : it is worth assigning error codes to specific messages. Creating an include file which #defined the first error as 1 and continues upwards is the wrong thing to do this file will inevitable be included in every other file, so whenever you add a new error the whole project will need rebuilding 4. A better solution is shown by Oracle, Sybase and other database vendors. Here, areas of functionality are assigned short text codes, e.g. SQL for query language functionality, NET for network functionality and so on. Within each area a set of numeric codes is allocated, so we have errors like SQL0001, SQL0002, etc. 3 I state this not as an objective of software but as a reality. 4 This is the exact example John Lakos gives (Large Scale C++ Software Design, 1996) of a practice that will lead to problems on large projects.

? Keep a central record of error messages your system can issue : this is invaluable when documenting the system and running a help desk to support the system. Even where the software does not represent a commercial product it reduces the burden on anyone who has to support the system by living with a pager and/or mobile phone!? When devising an error code scheme, and an error message document make sure they are easy to work with and expand. The last thing you want is a developer saying: It s too much hassle to add a new error message and number for this case, this existing code and message is almost right so I ll just reuse that. For once, we don t want to re-use code. Re-using this code will lead to confusion for the technical author and help desk, let alone if the text is translated to another language where it can t do double service! Now for some code... One of the problems with handling exceptions with C++ under Windows NT is that the existence of two exception mechanisms. The C++ mechanism which I m sure all Overload readers know and love, and the NT structured exception mechanism, this is a little like a UNIX signal, when NT encounters an exception (e.g divide by zero, memory corruption) it raises a structured exception. An NT structured exception is an unsigned integer which identifies the condition. It may be caught with a C++ catch-all (catch(...)) but so is everything else. Further, the stack management semantics are different, an NT structured exception will not unwind the stack. This makes it difficult to compile code with both mechanisms in use indeed Visual C++ with issue a warning message at the very least. The solution, as shown here, is to install an exception translator. This is done by registering a function callback using the _set_se_translator function: _set_se_translator( Translator ) Once installed, NT will call the translator whenever it hits a structured exception. (Shown in the listing NtSeTranslator.h &.cpp.) This provides us with an opportunity to create an object to represent the exception and throw this. A problem occurs as NT calls the function for each stack frame as it clears the stack, hence the translator will be called multiple times so we cannot embed information within the exception object as a new one is created and thrown at each stack level. We can however, catch a translated exception using regular C++ catch semantics and obtain access the error code. We can also stop the stack unwind when the catch occurs. The code is in two parts. Firstly the actual translator function, which is an large ugly switch statement. Secondly, the translator class SeTranslator. SeTranslator implements an allocation is initialisation metaphore to install the translator when an object of SeTranslator is installed. Normally, I declare one of these just inside the first try block of my code. try { // install a translator Accu::SeTranslator translator; int *ptr = NULL;

std::cout << "Goodbye crewl world..." return 0; << *ptr << std::endl; } catch(accu::structuredexception& exp) { std::cerr << "Something happened: " << exp.what() << std::endl; return 1; } I suspect that UNIX signals could be wrapped in such a way to similarly throw an exception when received. This raises an interesting cross platform handling technique. I also include an exception class, StructuredException (in listing StructuredException.h and.cpp), derived from std::exception which is thrown when an NT structured exception is throw. Finally, over the time I have been using these classes the most useful facility is one which is not immediately obvious. Within the debugger, place a break point inside the translator function. In the event of a structured exception (e.g. de-referencing a null pointer) the translator is called and the breakpoint encountered resulting in a debugger trap at the point after the error occurred with a full stack trace available and watch windows. Conclusion I hope I have convinced you that when thinking of exceptions we need to think in terms of cause and effect, the cause maps to the developers view of the exception and the effect maps to the users view of what happened. Under Windows NT the effect can sometimes be all to obvious and the cause unknown, however, by bringing the NT exception handling mechanism into the C++ world we can, once again, deal with cause and effect. (C) Allan Kelly 1999