Where should UI errors be generated and printed from? Log errors?

Function A() calls B() calls C(), which encounters an error. Which function writes to the log and which function reports to the user?

My first inclination is that all functions should write to the log, and that the inner-most UI-facing function should be responsible for outputting the error to the user. However, the fix needs to be done in C(), so perhaps instead of having an super-long log file which will take a while to parse, I should simply have the function which encountered the error log the error and the parameters used to call it.

Likewise, I’m not too convinced that the inner-most UI-facing function should output the error (consider CLI apps, as opposed to web or GUI apps). That was more of a gut-feeling decision, so any insight into actually engineering a solution would be appreciated.

As there are two distinct audiences for the error report, with completely different information needs, it makes sense to have the error reporting at multiple levels.

On the one hand, there are the developers who need to know exactly where the error was detected and all the nitty gritty details of the error itself. As the developers are also the ones who analyse the log files, it makes most sense to produce a log for an error as soon as it is detected, where most of the relevant information for the developers is still at hand and can be incorporated in the log.

On the other hand, the end-users of the application don’t really care about what went wrong. They just want to know if the function they requested succeeded and if not, what they can do to make it succeed the next time.
This information is at a higher level of abstraction than the usual error-detection code and usually not even known at the level where the error is first detected.
For example, if there is an error when saving a file, the code responsible for writing the data to disk can’t know if the save action was triggered automatically or by explicit request from the user, but that is important information when deciding how to inform the end-user of the problem.

In summary, error reports should be generated at the level where the information is at the right abstraction level to provide a meaningful and helpful report to the intended audience of the report.

Additionally, human readable texts meant for end-users should be generated in the UI components of the application to ensure that only the UI is affected if you need to support additional languages for the end users.

Logging

Let me start with the logging. Well as I’m sure you’re aware, there are various logging levels which most libraries support: Debug, Info, Warning, and Error.

My approach is that Debug output should show all information that I, the programmer, would want to see. The user using your program isn’t likely going to want to see that you entered a specific method in the GUI, but I would in the case of a crash. If you have no way of retrieving the stack trace of the crash, then the next best thing is to print out to the log the entry and exit of every method in your program with log level debug.

In your example, that means a log with the following output:

DEBUG <timestamp>:  ClassA::A() : Entering A
DEBUG <timestamp>:  ClassB::B() : Entering B
DEBUG <timestamp>:  ClassC::C() : Entering C
DEBUG <timestamp>:  ClassC::C() : Exiting C   // These don't show
DEBUG <timestamp>:  ClassB::B() : Exiting B   // in the case of 
DEBUG <timestamp>:  ClassA::A() : Exiting A   // an error in C.

Log level Info is information that I would consider to be relevant to functionality of the program. Suppose for the purposes of this example that the objective of A is to perform an operation using a selected database, B is a means to view existing database connections and to create new database connections, and C is the specific information pertaining to a new database and a way of testing said connection.

Relevant Info level log messages for me would be:

INFO <timestamp>:  ClassC::C() : Saved database connection "localhost".
INFO <timestamp>:  ClassA::A() : Performing transaction using database connection "localhost".
INFO <timestamp>:  ClassA::A() : Transaction complete using database connection "localhost".

Notice that these are messages you would also likely want to show to the user throughout the program (albeit a little verbose). For me that is the difference between Debug and Info: whether or not the user may also want to see this information. Obviously logging levels warning and error should also be both logged and shown to the user.

WARNING <timestamp>:  ClassC::C() : Connection test for "localhost" failed.

What I typically do in my programs is take an optional parameter which determines at what logging level I should present messages to the user with a default value of Info. If the user does not want a verbose interface, he or she can set it to Warning instead and see only warnings and errors, and I can use it in order to output debugging information, for example. In that case, just be sure to provide an alternative indicator that a particular task is finished (execute button becomes disabled during elaboration then afterwards becomes again enabled, for instance).

Exceptions

That said, how do I approach exceptions? It depends on the context of the error. If ClassC handles creation of new database connections and upon testing the connection, throws an exception, I would want to handle that sql exception inside ClassC since I am expecting potential problems. Notice that I would only handle a sql exception. If the problem were another that I wasn’t expecting, it would slip through Class C and consequently move to ClassB. ClassB may decide to catch exceptions related to missing drivers, since that is not entirely unexpected, and I wouldn’t want such problems to be caught at lower levels.

However, assuming it is not either, we hit ClassA who’s only role in calling ClassB was to allow the user the possibility to create new database connections. If an exception hits ClassA, something serious has happened. In such instances, what I typically do is to catch any exception, write the error and its stacktrace (if possible) to the log, show an unexpected error message to the user, then rethrow the exception. In my personal opinion, it is irresponsible to catch all exceptions without being prepared to rethrow it, since it is correct that unexpected errors are still thrown.

The important point to note here is the level of responsibility. The exceptions that I’m expecting are handled locally while unexpected exceptions in the context of my class are allowed to move up the chain. In the absolute worst case, be sure to try to log the error and show an error message to the user. Combine this with precision logging, and you’re sure to be able to trace your steps to the place of error in most cases.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Where should UI errors be generated and printed from? Log errors?

Function A() calls B() calls C(), which encounters an error. Which function writes to the log and which function reports to the user?

My first inclination is that all functions should write to the log, and that the inner-most UI-facing function should be responsible for outputting the error to the user. However, the fix needs to be done in C(), so perhaps instead of having an super-long log file which will take a while to parse, I should simply have the function which encountered the error log the error and the parameters used to call it.

Likewise, I’m not too convinced that the inner-most UI-facing function should output the error (consider CLI apps, as opposed to web or GUI apps). That was more of a gut-feeling decision, so any insight into actually engineering a solution would be appreciated.

As there are two distinct audiences for the error report, with completely different information needs, it makes sense to have the error reporting at multiple levels.

On the one hand, there are the developers who need to know exactly where the error was detected and all the nitty gritty details of the error itself. As the developers are also the ones who analyse the log files, it makes most sense to produce a log for an error as soon as it is detected, where most of the relevant information for the developers is still at hand and can be incorporated in the log.

On the other hand, the end-users of the application don’t really care about what went wrong. They just want to know if the function they requested succeeded and if not, what they can do to make it succeed the next time.
This information is at a higher level of abstraction than the usual error-detection code and usually not even known at the level where the error is first detected.
For example, if there is an error when saving a file, the code responsible for writing the data to disk can’t know if the save action was triggered automatically or by explicit request from the user, but that is important information when deciding how to inform the end-user of the problem.

In summary, error reports should be generated at the level where the information is at the right abstraction level to provide a meaningful and helpful report to the intended audience of the report.

Additionally, human readable texts meant for end-users should be generated in the UI components of the application to ensure that only the UI is affected if you need to support additional languages for the end users.

Logging

Let me start with the logging. Well as I’m sure you’re aware, there are various logging levels which most libraries support: Debug, Info, Warning, and Error.

My approach is that Debug output should show all information that I, the programmer, would want to see. The user using your program isn’t likely going to want to see that you entered a specific method in the GUI, but I would in the case of a crash. If you have no way of retrieving the stack trace of the crash, then the next best thing is to print out to the log the entry and exit of every method in your program with log level debug.

In your example, that means a log with the following output:

DEBUG <timestamp>:  ClassA::A() : Entering A
DEBUG <timestamp>:  ClassB::B() : Entering B
DEBUG <timestamp>:  ClassC::C() : Entering C
DEBUG <timestamp>:  ClassC::C() : Exiting C   // These don't show
DEBUG <timestamp>:  ClassB::B() : Exiting B   // in the case of 
DEBUG <timestamp>:  ClassA::A() : Exiting A   // an error in C.

Log level Info is information that I would consider to be relevant to functionality of the program. Suppose for the purposes of this example that the objective of A is to perform an operation using a selected database, B is a means to view existing database connections and to create new database connections, and C is the specific information pertaining to a new database and a way of testing said connection.

Relevant Info level log messages for me would be:

INFO <timestamp>:  ClassC::C() : Saved database connection "localhost".
INFO <timestamp>:  ClassA::A() : Performing transaction using database connection "localhost".
INFO <timestamp>:  ClassA::A() : Transaction complete using database connection "localhost".

Notice that these are messages you would also likely want to show to the user throughout the program (albeit a little verbose). For me that is the difference between Debug and Info: whether or not the user may also want to see this information. Obviously logging levels warning and error should also be both logged and shown to the user.

WARNING <timestamp>:  ClassC::C() : Connection test for "localhost" failed.

What I typically do in my programs is take an optional parameter which determines at what logging level I should present messages to the user with a default value of Info. If the user does not want a verbose interface, he or she can set it to Warning instead and see only warnings and errors, and I can use it in order to output debugging information, for example. In that case, just be sure to provide an alternative indicator that a particular task is finished (execute button becomes disabled during elaboration then afterwards becomes again enabled, for instance).

Exceptions

That said, how do I approach exceptions? It depends on the context of the error. If ClassC handles creation of new database connections and upon testing the connection, throws an exception, I would want to handle that sql exception inside ClassC since I am expecting potential problems. Notice that I would only handle a sql exception. If the problem were another that I wasn’t expecting, it would slip through Class C and consequently move to ClassB. ClassB may decide to catch exceptions related to missing drivers, since that is not entirely unexpected, and I wouldn’t want such problems to be caught at lower levels.

However, assuming it is not either, we hit ClassA who’s only role in calling ClassB was to allow the user the possibility to create new database connections. If an exception hits ClassA, something serious has happened. In such instances, what I typically do is to catch any exception, write the error and its stacktrace (if possible) to the log, show an unexpected error message to the user, then rethrow the exception. In my personal opinion, it is irresponsible to catch all exceptions without being prepared to rethrow it, since it is correct that unexpected errors are still thrown.

The important point to note here is the level of responsibility. The exceptions that I’m expecting are handled locally while unexpected exceptions in the context of my class are allowed to move up the chain. In the absolute worst case, be sure to try to log the error and show an error message to the user. Combine this with precision logging, and you’re sure to be able to trace your steps to the place of error in most cases.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Where should UI errors be generated and printed from? Log errors?

Function A() calls B() calls C(), which encounters an error. Which function writes to the log and which function reports to the user?

My first inclination is that all functions should write to the log, and that the inner-most UI-facing function should be responsible for outputting the error to the user. However, the fix needs to be done in C(), so perhaps instead of having an super-long log file which will take a while to parse, I should simply have the function which encountered the error log the error and the parameters used to call it.

Likewise, I’m not too convinced that the inner-most UI-facing function should output the error (consider CLI apps, as opposed to web or GUI apps). That was more of a gut-feeling decision, so any insight into actually engineering a solution would be appreciated.

As there are two distinct audiences for the error report, with completely different information needs, it makes sense to have the error reporting at multiple levels.

On the one hand, there are the developers who need to know exactly where the error was detected and all the nitty gritty details of the error itself. As the developers are also the ones who analyse the log files, it makes most sense to produce a log for an error as soon as it is detected, where most of the relevant information for the developers is still at hand and can be incorporated in the log.

On the other hand, the end-users of the application don’t really care about what went wrong. They just want to know if the function they requested succeeded and if not, what they can do to make it succeed the next time.
This information is at a higher level of abstraction than the usual error-detection code and usually not even known at the level where the error is first detected.
For example, if there is an error when saving a file, the code responsible for writing the data to disk can’t know if the save action was triggered automatically or by explicit request from the user, but that is important information when deciding how to inform the end-user of the problem.

In summary, error reports should be generated at the level where the information is at the right abstraction level to provide a meaningful and helpful report to the intended audience of the report.

Additionally, human readable texts meant for end-users should be generated in the UI components of the application to ensure that only the UI is affected if you need to support additional languages for the end users.

Logging

Let me start with the logging. Well as I’m sure you’re aware, there are various logging levels which most libraries support: Debug, Info, Warning, and Error.

My approach is that Debug output should show all information that I, the programmer, would want to see. The user using your program isn’t likely going to want to see that you entered a specific method in the GUI, but I would in the case of a crash. If you have no way of retrieving the stack trace of the crash, then the next best thing is to print out to the log the entry and exit of every method in your program with log level debug.

In your example, that means a log with the following output:

DEBUG <timestamp>:  ClassA::A() : Entering A
DEBUG <timestamp>:  ClassB::B() : Entering B
DEBUG <timestamp>:  ClassC::C() : Entering C
DEBUG <timestamp>:  ClassC::C() : Exiting C   // These don't show
DEBUG <timestamp>:  ClassB::B() : Exiting B   // in the case of 
DEBUG <timestamp>:  ClassA::A() : Exiting A   // an error in C.

Log level Info is information that I would consider to be relevant to functionality of the program. Suppose for the purposes of this example that the objective of A is to perform an operation using a selected database, B is a means to view existing database connections and to create new database connections, and C is the specific information pertaining to a new database and a way of testing said connection.

Relevant Info level log messages for me would be:

INFO <timestamp>:  ClassC::C() : Saved database connection "localhost".
INFO <timestamp>:  ClassA::A() : Performing transaction using database connection "localhost".
INFO <timestamp>:  ClassA::A() : Transaction complete using database connection "localhost".

Notice that these are messages you would also likely want to show to the user throughout the program (albeit a little verbose). For me that is the difference between Debug and Info: whether or not the user may also want to see this information. Obviously logging levels warning and error should also be both logged and shown to the user.

WARNING <timestamp>:  ClassC::C() : Connection test for "localhost" failed.

What I typically do in my programs is take an optional parameter which determines at what logging level I should present messages to the user with a default value of Info. If the user does not want a verbose interface, he or she can set it to Warning instead and see only warnings and errors, and I can use it in order to output debugging information, for example. In that case, just be sure to provide an alternative indicator that a particular task is finished (execute button becomes disabled during elaboration then afterwards becomes again enabled, for instance).

Exceptions

That said, how do I approach exceptions? It depends on the context of the error. If ClassC handles creation of new database connections and upon testing the connection, throws an exception, I would want to handle that sql exception inside ClassC since I am expecting potential problems. Notice that I would only handle a sql exception. If the problem were another that I wasn’t expecting, it would slip through Class C and consequently move to ClassB. ClassB may decide to catch exceptions related to missing drivers, since that is not entirely unexpected, and I wouldn’t want such problems to be caught at lower levels.

However, assuming it is not either, we hit ClassA who’s only role in calling ClassB was to allow the user the possibility to create new database connections. If an exception hits ClassA, something serious has happened. In such instances, what I typically do is to catch any exception, write the error and its stacktrace (if possible) to the log, show an unexpected error message to the user, then rethrow the exception. In my personal opinion, it is irresponsible to catch all exceptions without being prepared to rethrow it, since it is correct that unexpected errors are still thrown.

The important point to note here is the level of responsibility. The exceptions that I’m expecting are handled locally while unexpected exceptions in the context of my class are allowed to move up the chain. In the absolute worst case, be sure to try to log the error and show an error message to the user. Combine this with precision logging, and you’re sure to be able to trace your steps to the place of error in most cases.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Where should UI errors be generated and printed from? Log errors?

Function A() calls B() calls C(), which encounters an error. Which function writes to the log and which function reports to the user?

My first inclination is that all functions should write to the log, and that the inner-most UI-facing function should be responsible for outputting the error to the user. However, the fix needs to be done in C(), so perhaps instead of having an super-long log file which will take a while to parse, I should simply have the function which encountered the error log the error and the parameters used to call it.

Likewise, I’m not too convinced that the inner-most UI-facing function should output the error (consider CLI apps, as opposed to web or GUI apps). That was more of a gut-feeling decision, so any insight into actually engineering a solution would be appreciated.

As there are two distinct audiences for the error report, with completely different information needs, it makes sense to have the error reporting at multiple levels.

On the one hand, there are the developers who need to know exactly where the error was detected and all the nitty gritty details of the error itself. As the developers are also the ones who analyse the log files, it makes most sense to produce a log for an error as soon as it is detected, where most of the relevant information for the developers is still at hand and can be incorporated in the log.

On the other hand, the end-users of the application don’t really care about what went wrong. They just want to know if the function they requested succeeded and if not, what they can do to make it succeed the next time.
This information is at a higher level of abstraction than the usual error-detection code and usually not even known at the level where the error is first detected.
For example, if there is an error when saving a file, the code responsible for writing the data to disk can’t know if the save action was triggered automatically or by explicit request from the user, but that is important information when deciding how to inform the end-user of the problem.

In summary, error reports should be generated at the level where the information is at the right abstraction level to provide a meaningful and helpful report to the intended audience of the report.

Additionally, human readable texts meant for end-users should be generated in the UI components of the application to ensure that only the UI is affected if you need to support additional languages for the end users.

Logging

Let me start with the logging. Well as I’m sure you’re aware, there are various logging levels which most libraries support: Debug, Info, Warning, and Error.

My approach is that Debug output should show all information that I, the programmer, would want to see. The user using your program isn’t likely going to want to see that you entered a specific method in the GUI, but I would in the case of a crash. If you have no way of retrieving the stack trace of the crash, then the next best thing is to print out to the log the entry and exit of every method in your program with log level debug.

In your example, that means a log with the following output:

DEBUG <timestamp>:  ClassA::A() : Entering A
DEBUG <timestamp>:  ClassB::B() : Entering B
DEBUG <timestamp>:  ClassC::C() : Entering C
DEBUG <timestamp>:  ClassC::C() : Exiting C   // These don't show
DEBUG <timestamp>:  ClassB::B() : Exiting B   // in the case of 
DEBUG <timestamp>:  ClassA::A() : Exiting A   // an error in C.

Log level Info is information that I would consider to be relevant to functionality of the program. Suppose for the purposes of this example that the objective of A is to perform an operation using a selected database, B is a means to view existing database connections and to create new database connections, and C is the specific information pertaining to a new database and a way of testing said connection.

Relevant Info level log messages for me would be:

INFO <timestamp>:  ClassC::C() : Saved database connection "localhost".
INFO <timestamp>:  ClassA::A() : Performing transaction using database connection "localhost".
INFO <timestamp>:  ClassA::A() : Transaction complete using database connection "localhost".

Notice that these are messages you would also likely want to show to the user throughout the program (albeit a little verbose). For me that is the difference between Debug and Info: whether or not the user may also want to see this information. Obviously logging levels warning and error should also be both logged and shown to the user.

WARNING <timestamp>:  ClassC::C() : Connection test for "localhost" failed.

What I typically do in my programs is take an optional parameter which determines at what logging level I should present messages to the user with a default value of Info. If the user does not want a verbose interface, he or she can set it to Warning instead and see only warnings and errors, and I can use it in order to output debugging information, for example. In that case, just be sure to provide an alternative indicator that a particular task is finished (execute button becomes disabled during elaboration then afterwards becomes again enabled, for instance).

Exceptions

That said, how do I approach exceptions? It depends on the context of the error. If ClassC handles creation of new database connections and upon testing the connection, throws an exception, I would want to handle that sql exception inside ClassC since I am expecting potential problems. Notice that I would only handle a sql exception. If the problem were another that I wasn’t expecting, it would slip through Class C and consequently move to ClassB. ClassB may decide to catch exceptions related to missing drivers, since that is not entirely unexpected, and I wouldn’t want such problems to be caught at lower levels.

However, assuming it is not either, we hit ClassA who’s only role in calling ClassB was to allow the user the possibility to create new database connections. If an exception hits ClassA, something serious has happened. In such instances, what I typically do is to catch any exception, write the error and its stacktrace (if possible) to the log, show an unexpected error message to the user, then rethrow the exception. In my personal opinion, it is irresponsible to catch all exceptions without being prepared to rethrow it, since it is correct that unexpected errors are still thrown.

The important point to note here is the level of responsibility. The exceptions that I’m expecting are handled locally while unexpected exceptions in the context of my class are allowed to move up the chain. In the absolute worst case, be sure to try to log the error and show an error message to the user. Combine this with precision logging, and you’re sure to be able to trace your steps to the place of error in most cases.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật