If an exception is thrown deep in your code and no one sees the error message, and no one checks the error log, etc. -- did that exception ever exist in any meaningful way? Do we like to show_error or throw exceptions in our code? Do you guys write text logs or do you use a database to insert error/log messages? I'm hoping to get a better idea of how you folks deal with errors in your code.

I expect this could be quite an involved discussion so I'll focus in a specific question for now. I'm creating a db table called db_log that will include a few fields:
id - int, primary key
severity - tinyint (and my question is about this column!)
type - a way of categorizing errors to possibly reduce the error message volume if some party wants to focus on a specific type of error. E.g., it might be PAYMENT_GATEWAY or CLOUD_API or MAIL_FAILURE or something
file - the file in which the error message was generated
line - the line in the code that wrote the error message
creation_microtime - a float output by [man]microtime[/man] that corresponds to a nix timestamp records when the error happened
log_entry - a text field that contains the textual detail of the error message. might contain an exception converted to string, a stack trace, or just a terse text message.

So here's my question: What are good constant names for the severity levels? Although I will be writing tinyints into the db, I want to refer to them in my code by some constant name. The severity options should represent a sequence. I.e., DEBUG is not as important as CRITICAL which is not as important maybe as DEFCON_5_EMERGENCY. I note that Apache's LogLevel has numerous settings.
emerg - Emergencies - system is unusable
alert - Action must be taken immediately
crit - Critical Conditions
error - Error conditions
warn - Warning conditions
notice - Normal but significant condition
info - Informational
debug - Debug-level messages

mod_rewrite has 10 levels of verbosity for its RewriteLogLevel, from 0 (off) to 9 (everything).

I'll point out too that the 'severity' of a log entry may be different for different folks in one's organization. A log entry that says "the credit card has expired" is no problem at all for a developer as long as the API responded with well-formed data response. For one's accounting team, however, it could be red alert if the goods have already been shipped.

And then there's the the question of what to do if you can't connect to the database. Obviously, trying to write a db_log table is not going to happen. What to do in this case? Send an email? That seems like a good way to get a bazillion emails when there's a db problem.

    • debug - Debug-level messages

    • info - Informational

    • notice - Normal but significant condition

    • warn - Warning conditions

    • error - Error conditions

    • crit - Critical Conditions

    • alert - Action must be taken immediately

    • emerg - Emergencies - system is unusable

    •    - System failed so hard it failed to even record a message

      It should be noted that the way I handle errors is directly influenced by you in my project thread.

      Because of the advice provided I have become accustomed to using exceptions and the (very easy) ability to create custom exceptions allows for a fine-grained approach to error checking and handling. With that in mind I use it quite a bit. Before I refactored my code I was simply just writing the exception's message to the PHP error log. Once I refactored my code I created a log table in my database much like what you are doing. The fields differ a bit but the overall idea is definitely there:

      • id
      • exception_type (basically I use get_class() on the exception so I know what type of exception it was)
      • timestamp (datetime - way better than a Unix timestamp)
      • exception_trace (just a string dump of the stack trace)
      • user_message (the message that was basically included when throwing the exception, AKA, $e->getMessage())
      • line
      • file

      Not going to lie, I hadn't thought about severity of the error, but I feel like that could easily change based on context and is difficult to quantify. In my eyes I rather see the list of errors and decide for myself what is "critical" and what is "trivial" (you basically addressed this in your second last paragraph).

      To answer your question:

      sneakyimp;11051709 wrote:

      If an exception is thrown deep in your code and no one sees the error message, and no one checks the error log, etc. -- did that exception ever exist in any meaningful way?

      Philosophically, if the error didn't affect the user and it didn't affect the application, then it really didn't exist, even if it was logged. At that point I would reevaluate what that error is really for and the condition that causes it, since we're now challenging its existence.

      sneakyimp;11051709 wrote:

      And then there's the the question of what to do if you can't connect to the database. Obviously, trying to write a db_log table is not going to happen. What to do in this case? Send an email? That seems like a good way to get a bazillion emails when there's a db problem.

      Heh I just ran into this last night when I was cleaning up my error_log() messages. What I did in this case was simply output a die() with an error message about connecting to the database and I wrote the info to the PHP error log, because to me that's an actual error - that shouldn't be happening, ever, and since the entire application is dependent on the database, it should be right up front and centre that it failed to connect. An email could work, but as you noted, if the database goes down and you have hundreds of people trying to access the application, then you're going to get hundreds of emails, and we all know people will keep hitting refresh, so yeah, your inbox is going to get really full really fast. At least with an error log you can prune it pretty quickly and easily.

        Bonesnap;11051721 wrote:

        It should be noted that the way I handle errors is directly influenced by you in my project thread.

        I appreciate your fresh thoughts on the matter.

        Bonesnap;11051721 wrote:

        Because of the advice provided I have become accustomed to using exceptions and the (very easy) ability to create custom exceptions allows for a fine-grained approach to error checking and handling. With that in mind I use it quite a bit. Before I refactored my code I was simply just writing the exception's message to the PHP error log. Once I refactored my code I created a log table in my database much like what you are doing. The fields differ a bit but the overall idea is definitely there:
        id
        exception_type (basically I use get_class() on the exception so I know what type of exception it was)
        timestamp (datetime - way better than a Unix timestamp)
        exception_trace (just a string dump of the stack trace)
        user_message (the message that was basically included when throwing the exception, AKA, $e->getMessage())
        line
        * file

        I've never really bothered to define a whole bunch of exception types. I'm wondering if you find any specific advantages yet in having multiple Exception types? I'm also curious about what your catch blocks may look like in situations where you are trying to distinguish exception types.

        I also agree that datetimes are waaaaay more readable than unix timestamps, but would point out that a DateTime only provides time accuracy down to a whole second. I anticipate that I may encounter situations where two distinct process threads are working at the same time and milliseconds may matter. I've therefore chosen to use the output of [man]microtime(TRUE)[man] as my timestamp. I suppose I could order first by a DateTime and then by some autoincrementing primary key instead, but microtime seemed more precise.

        error_type (or event_type is what I'm calling it actually) in my case is going to be some string that pertains to the business at hand (accounting, sales, IT) rather than coding considerations (db, api, email). The whole point of these event types is to help categorize/filter/narrow-down the db_log contents for analysis or viewing.

        I've also got a user_friendly_id that is generated when I instantiate my db_log object within a script. This user_friendly_id will be common to all log entries written during the lifetime of the db_log object to make it easy to locate all db_log records that pertain to a given page request or script execution. The reason I call it user_friendly_id (which is, admittedly a poor name) is because it can be shown to a user as a readable token without showing any sensitive information. I still wonder a bit if it's safe to use [man]uniqid[/man] to generate this id but it seems OK. E.g.:

        $log = new db_log($this->db); // this operation generates a user_friendly_id
        
        $log->write("Here is a log entry message", "some-event-type", SEVERITY_LOW); // creates a db log entry
        
        $log->write("Here is another message", "some-event-type", SEVERITY_MEDIUM); // creates a db log entry which shares user_friendly_id with the last entry
        
        if ($there_is_a_big_problem) {
          $log->write("Here is another message", "some-event-type", SEVERITY_HIGH); // also shares user_friendly_id with the last entry
          echo "There was a big problem. Please contact tech support. Your issue id is " . $log->user_friendly_id;
        }
        
        Bonesnap;11051721 wrote:

        Not going to lie, I hadn't thought about severity of the error, but I feel like that could easily change based on context and is difficult to quantify. In my eyes I rather see the list of errors and decide for myself what is "critical" and what is "trivial" (you basically addressed this in your second last paragraph).

        As I posted, the idea of severity relates to log verbosity. I've seen this concept in many august and respectable software projects. If it's good enough for Apache, it's good enough for me. To me, it provides two immediately obvious benefits:
        I can establish some threshold of importance to limit the volume of messages written to my db_log. This may be very important if the db_log proves to be a bottleneck. Up the threshold, reduce the volume of messages being written to my busy db.
        Viewing the log, I can limit the volume of information. If I need more detail, I can drill deeper if I must -- at least up to the point where I reach the log threshold.

        Bonesnap;11051721 wrote:

        Philosophically, if the error didn't affect the user and it didn't affect the application, then it really didn't exist, even if it was logged. At that point I would reevaluate what that error is really for and the condition that causes it, since we're now challenging its existence.

        My production code right now is writing so many text logs right now. They almost never get examined. When something goes wrong, though, they are critical. And they don't seem to be hurting performance so there doesn't seem to be any harm. Looking into them, however, is a chore. Login via ssh, run some grep commands, inspect raw text, etc. No queries possible, no dashboards for employees easily constructed, etc. The reason for severity again is such that some trivial, never-noticed message may be written to the db_log but when the time comes that we actually need that log entry, we can dig deeper and it will show itself. On the other hand, I'm concerned about the db being bottleneck. On the other hand blah blah blah. Log files....how much logging do you need? Seems adjustability is important.

        Bonesnap;11051721 wrote:

        Heh I just ran into this last night when I was cleaning up my error_log() messages. What I did in this case was simply output a die() with an error message about connecting to the database and I wrote the info to the PHP error log, because to me that's an actual error - that shouldn't be happening, ever, and since the entire application is dependent on the database, it should be right up front and centre that it failed to connect. An email could work, but as you noted, if the database goes down and you have hundreds of people trying to access the application, then you're going to get hundreds of emails, and we all know people will keep hitting refresh, so yeah, your inbox is going to get really full really fast. At least with an error log you can prune it pretty quickly and easily.

        I like your idea of using [man]error_log[/man] for these and I'm adopting that approach. I've made a variation of my $log->write method, $log->write_no_exception, which has a try/catch block to catch any exceptions that might get thrown trying to write the db log. If it catches any exceptions trying to write the db log, it just uses error_log instead. I can use it if I feel that db problems are likely--or any time at all really. Sort of depends on whether I want an exception thrown if I can't write the db log.

        As for the php error_log, I don't think it needs pruning under most setups I've deal with. log_rotate is configured to automagically rotate the php/apache logs.
        EDIT: but is an unexamined error_log useful? Sort of harks back to my first question.

          Bonesnap;11051773 wrote:

          I will respond properly when I have more time (AKA, not putting off work lol), but I just wanted to point out that if you are using MySQL 5.6.4+ then datetime has support for fractional seconds up to 6 decimal places.

          Niiiiiiiice.

          More good news: I updated my workstation to Ubuntu 14.04 and MySQL version 5.6.19 is installed. Yay.

            I would say that the main advantage of multiple exception types is that it allows you to catch them (and handle them) separately.

            try
            {
                // ...
            }
            catch(ThisException $e)
            {
                // ... no big deal, keep going, just log an error
            }
            catch(ThatException $e)
            {
                // ... better display a nice error message here with specifics about this sort of problem
            }
            catch(Exception $e)
            {
                // ...holy crap, how did we get here? Send email to sysadmin and terminate app!
                exit();
            }
            
              NogDog;11051779 wrote:

              I would say that the main advantage of multiple exception types is that it allows you to catch them (and handle them) separately.

              try
              {
                  // ...
              }
              catch(ThisException $e)
              {
                  // ... no big deal, keep going, just log an error
              }
              catch(ThatException $e)
              {
                  // ... better display a nice error message here with specifics about this sort of problem
              }
              catch(Exception $e)
              {
                  // ...holy crap, how did we get here? Send email to sysadmin and terminate app!
                  exit();
              }
              

              Interesting. I tend to throw exceptions when something unacceptable happens. It hadn't occurred to me to throw exceptions under "minor" circumstances (e.g., log an error and keep going in your example). Exceptions and try/catch blocks represent a pretty different control flow from defining function results and using IF blocks. This is really the point of my post here. To try and have an 'awakening' of sorts regarding error handling. Choosing what to do when errors happen is one of the tricky bits of programming. Logging them makes sense because you might need details later when people start complaining about something or if you notice a serious problem in your data perhaps. Control flow is another consideration.

              From what I can tell, the primary benefit of throwing Exceptions at all (even the plain vanilla Exception) is that you don't have to constantly check function return values to know if you can proceed or not. An exception thrown somewhere down in your code says "hey buddy something went wrong" and code execution will jump all the way back up your call stack to the first catch block it finds (if any). Coding this way is soooooo much easier than always checking the result of every function to see if there's some kind of error condition and then creating some kind of IF/ELSE logic in your code. Also, back up at the higher level of your code where the exception gets caught, you receive information directly about the problem from the Exception itself rather than having to propagate some error message back up via return values or some other complicated side chain.

                sneakyimp wrote:

                I tend to throw exceptions when something unacceptable happens. It hadn't occurred to me to throw exceptions under "minor" circumstances (e.g., log an error and keep going in your example).

                No, from the called function's perspective, it is "major" enough to warrant that the flow of control be interrupted. It is just that at the point of the catch, the caller is able to determine that in the given context it is sufficiently "minor" so that it can be suppressed with some logging in case it turns out to be not so.

                  laserlight;11051789 wrote:

                  No, from the called function's perspective, it is "major" enough to warrant that the flow of control be interrupted. It is just that at the point of the catch, the caller is able to determine that in the given context it is sufficiently "minor" so that it can be suppressed with some logging in case it turns out to be not so.

                  Good point. As I was somewhat ineptly babbling, one of the great advantages/differences of throwing an exception is the radical alteration to your control flow. The exact nature of this radical alteration is still slowly sinking in. If I throw an exception that is not directly in some try/catch block, the current function (if any) will be abruptly interrupted and we got shooting back up the call stack until we either end up in some try/catch block or we run out of scope. On the other hand, If we want to keep call execution in the current function, we can just add a try/catch block in it. I think 'try/catch' is one of the best-named code structures: "Try this. If anything goes wrong do this little bit." I've never really had occasion to use finally. Still wondering what the circumstances might be where one would use that. I'm imagining (without any real understanding) that a finally block might be used to clean up some allocated memory or something in C++ or something.

                    sneakyimp wrote:

                    I've never really had occasion to use finally. Still wondering what the circumstances might be where one would use that. I'm imagining (without any real understanding) that a finally block might be used to clean up some allocated memory or something in C++ or something.

                    The issue is that while garbage collection handles the memory resource, other resources might need to be handled too, hence such handling can be placed in a finally block. C++ has the Resource Acquisition Is Initialisation (RAII) idiom that ties resource lifetime with the lifetime of a stack based object, so a finally block is unnecessary as non-memory resources can be similiarly handled, though sometimes it may be more convenient.

                      sneakyimp;11051767 wrote:

                      I've never really bothered to define a whole bunch of exception types. I'm wondering if you find any specific advantages yet in having multiple Exception types? I'm also curious about what your catch blocks may look like in situations where you are trying to distinguish exception types.

                      The example that NogDog posted is almost identical to what I am doing. I can see how it may look verbose or even messy with a ton of catch blocks, but I have found that my individual functions/methods are much, much cleaner. And, as NogDog noted, it allows you finer, granular control over what happens in the event something goes wrong. It is in some ways kind of like multiple return types, only your method still returns only one type but you're able to handle other ones.

                      sneakyimp;11051767 wrote:

                      As I posted, the idea of severity relates to log verbosity. I've seen this concept in many august and respectable software projects. If it's good enough for Apache, it's good enough for me. To me, it provides two immediately obvious benefits:
                      I can establish some threshold of importance to limit the volume of messages written to my db_log. This may be very important if the db_log proves to be a bottleneck. Up the threshold, reduce the volume of messages being written to my busy db.
                      Viewing the log, I can limit the volume of information. If I need more detail, I can drill deeper if I must -- at least up to the point where I reach the log threshold.

                      My production code right now is writing so many text logs right now. They almost never get examined. When something goes wrong, though, they are critical. And they don't seem to be hurting performance so there doesn't seem to be any harm. Looking into them, however, is a chore. Login via ssh, run some grep commands, inspect raw text, etc. No queries possible, no dashboards for employees easily constructed, etc. The reason for severity again is such that some trivial, never-noticed message may be written to the db_log but when the time comes that we actually need that log entry, we can dig deeper and it will show itself. On the other hand, I'm concerned about the db being bottleneck. On the other hand blah blah blah. Log files....how much logging do you need? Seems adjustability is important.

                      Hmm, I think we may be looking at logging from two different perspectives. I'm expecting nothing to be in my logs. In fact, when I see entries in my PHP error log, whether it's a notice or a fatal error, I immediately get stressed and anxious. My log should be 100% clean and empty (which has brought up issues where I work because no one there seems to care about notices or warnings, and the error log there has thousands of lines in it). The only time something should be written to the log is if something goes wrong, which I'd like to determine if it's severe or not. I don't do any "diagnostic" logging or anything like that, but maybe that will be implemented in the future, though I think I'd put those sort of messages into a different log as I am expecting those to be there.

                      sneakyimp;11051767 wrote:

                      I like your idea of using [man]error_log[/man] for these and I'm adopting that approach. I've made a variation of my $log->write method, $log->write_no_exception, which has a try/catch block to catch any exceptions that might get thrown trying to write the db log. If it catches any exceptions trying to write the db log, it just uses error_log instead. I can use it if I feel that db problems are likely--or any time at all really. Sort of depends on whether I want an exception thrown if I can't write the db log.

                      I use error_log() as a quick and dirty way to debug PHP scripts that are called via AJAX requests. It can also be combined with print_r (with the second value as TRUE) to be even more useful.

                      sneakyimp;11051767 wrote:

                      EDIT: but is an unexamined error_log useful? Sort of harks back to my first question.

                      I would say something is useless until it is needed. As you said earlier, if you wanted to drill down deeper you can. If you didn't log everything you wouldn't be able to do that. It's better to have it and not need it, than to need it and not have it. 🙂

                        Bonesnap;11051837 wrote:

                        The example that NogDog posted is almost identical to what I am doing. I can see how it may look verbose or even messy with a ton of catch blocks, but I have found that my individual functions/methods are much, much cleaner. And, as NogDog noted, it allows you finer, granular control over what happens in the event something goes wrong. It is in some ways kind of like multiple return types, only your method still returns only one type but you're able to handle other ones.

                        Yes it was my reaction that those catch blocks start to look verbose -- and on top of the extra code needed to define the other Exception types. And there's also the issue of remembering what the exception types are for and deciding what exception types are needed. I'm sort of craving a real-world example. I do not doubt this approach is useful (it's built into the language!). I think it's my lack of imagination which is holding me back here.

                        Bonesnap;11051837 wrote:

                        Hmm, I think we may be looking at logging from two different perspectives. I'm expecting nothing to be in my logs. In fact, when I see entries in my PHP error log, whether it's a notice or a fatal error, I immediately get stressed and anxious.

                        :p Haha this to me is a little funny. Makes you sound very fastidious (in a really likable way of course). I bet your code is really dependable.

                        I agree that we seem to have different perspectives on logging and I think the difference centers on error logging versus just "logging." When you are dealing with stuff that all runs on your own server, it is more reasonable to expect your code to work without errors. When you deal with payment gateways and cloud apis and stuff like that, things start to get messy. Sometimes you can't connect. Sometimes the remote system is down. Sometimes it just barfs when your cron job tries to spin up a server and there's no real explanation of what went wrong and even though you write your cron job to try and shut down servers that won't cooperate, sometimes a cloud server won't shut down for a week because the cloud API has a glitch. Payment gateways are super-messy. They typically have dozens of error codes that might come back, but some I've never actually seen. The full range of responses is really sort of staggering. Cards expire. Accounts get frozen. Sometimes the gateway says a purchase is "on hold" or something, without explaining what that means or how to deal with it. In these cases, I need to log the responses just in case the client says "we are having a problem that comes up every now and then" so I can go actually find what the incoming data looked like. This is why I have severity levels like DEBUG and INFO. These are not error conditions, they are merely extra detail, just in case I need extra detail.

                        Bonesnap;11051837 wrote:

                        My log should be 100% clean and empty (which has brought up issues where I work because no one there seems to care about notices or warnings, and the error log there has thousands of lines in it).

                        Haha NIGHTMARE. Some people just don't get it. Damn Philistines!

                        Bonesnap;11051837 wrote:

                        The only time something should be written to the log is if something goes wrong, which I'd like to determine if it's severe or not. I don't do any "diagnostic" logging or anything like that, but maybe that will be implemented in the future, though I think I'd put those sort of messages into a different log as I am expecting those to be there.

                        To me, a log is somewhere you store information that you need to diagnose and fix problems -- or to better understand how your code functions in a real-life situation.

                        Bonesnap;11051837 wrote:

                        I use error_log() as a quick and dirty way to debug PHP scripts that are called via AJAX requests. It can also be combined with print_r (with the second value as TRUE) to be even more useful.

                        I often use my own logging class to write a log on at least a project-specific basis and more often a project-and-process-specific basis. Looking through a gigantic error log on a complex project is a chore. Having log files broken out by functionality helps you get more quickly to the issue at hand. However, it can be somewhat untidy (and possibly maddening to some) to have a directory full of random log files with widely differing internal formats.

                        Bonesnap;11051837 wrote:

                        It's better to have it and not need it, than to need it and not have it. 🙂

                        Exactly!

                          sneakyimp;11051841 wrote:

                          Yes it was my reaction that those catch blocks start to look verbose -- and on top of the extra code needed to define the other Exception types. And there's also the issue of remembering what the exception types are for and deciding what exception types are needed. I'm sort of craving a real-world example. I do not doubt this approach is useful (it's built into the language!). I think it's my lack of imagination which is holding me back here.

                          // Because controllers don't care how a model gets the data
                          class DataException extends Exception {}
                          
                          if (extension_loaded('PDO')) {
                              // Because the model cares why it can't retrieve data for the caller
                              class PDOPrepareException extends PDOException {}
                              class PDOExecuteException extends PDOException {}
                          }
                          

                          There, I just defined a couple new exception types. Not a lot of "extra code needed to define the other Exception types". Additionally, there are many more in PHP besides the vanilla exception, such as UnexpectedValueException and InvalidArgumentException. I use them quite a bit. And you can nest exceptions creating a trace of where exceptions came from.

                          Real world example (trimmed down for public forum):

                          // SomeController:
                          try {
                              return array_map([$this, 'mapItemsToApi'], $this->model->getItems());
                          } catch (DataException $e) {
                              ErrorController::DatabaseDown();
                          } catch (Exception $e) {
                              // Something VERY unexpected and possibly very bad happened
                              Logger::LogException($e);
                              ErrorController::InternalServerError();
                          }
                          
                          // SomeModel
                          try {
                              $stmt = $PDO->prepare('SELECT * FROM items');
                              if ($stmt === false) {
                                  $err = $PDO->errorInfo();
                                  throw new PDOPrepareException($err[2], $err[1]);
                              }
                          
                          $result = $stmt->execute( );
                          if ($result === false) {
                              $err = $stmt->errorInfo();
                              throw new PDOExecuteException($err[2], $err[1]);
                          }
                          
                          return $result->fetchAll();
                          } catch (PDOException $e) {
                              Logger::LogException($e);
                              throw new DataException('DB Query failed!', $e->getCode(), $e);
                          }
                          
                          // Logger
                          class Logger {
                              public static function LogException(Exception $e) {
                                  switch (true) {
                                      case $e instanceof DataException:
                                           static::LogDataException($e);
                                           break;
                                       case $e instanceof SomeOtherException:
                                           // BLAH
                                       default:
                                           $type = gettype($e);
                                           Emailer::SendToAdmin('An unknown internal server error has occurred', <<<BODY
                          
                          <h1>An unrecognized or unhandled exception has occurred.</h1>
                          <br>
                          <h2>{$type} found in {$e->getFile()} on {$e->getLine()}</h2>
                          <h2><strong>{$e->getCode()}</strong> {$e->getMessage()}</h2>
                          <br>
                          <pre>{$e->getTraceAsString()}</pre>
                          
                          BODY;
                                  }
                              }
                          }
                          

                          Quite possibly overly simplified? But trying to demonstrate how using different exception types makes for easier determination of how to handle said exception... Hopefully the illustration helps some. I find exceptions to be the best. If I'm in a place where I don't care or need to handle an exception, I can just let it bubble right past my scope (notice how my model doesn't look for any Exceptions besides PDOExceptions (and those inheriting from it) but my controller does).

                            sneakyimp;11051841 wrote:

                            Yes it was my reaction that those catch blocks start to look verbose -- and on top of the extra code needed to define the other Exception types. And there's also the issue of remembering what the exception types are for and deciding what exception types are needed. I'm sort of craving a real-world example. I do not doubt this approach is useful (it's built into the language!). I think it's my lack of imagination which is holding me back here.

                            There's still a lot of verbosity in a tangle of if/else blocks, which usually reside in your functions/methods. This takes all that spaghetti code out of your methods and puts it in one place: where you call your method. I've been finding that my methods are waaaay shorter and therefore cleaner and easier to read than before. I'd have to go back and look, but I don't think I have an else statement in my methods anywhere.

                            Declaring new exceptions is, ahem, exceptionally easy. 🙂 Here's my file (Class.Exceptions.php) to create new exceptions:

                            <?php
                            class Invalid_Token_Exception extends Exception {}
                            class Token_Mismatch_Exception extends Exception {}
                            class Undefined_Token_Exception extends Exception {}
                            class Database_Connection_Exception extends Exception {}
                            class Invalid_Argument_Exception extends Exception {}
                            class Data_Exception extends Exception {}
                            class Duplicate_Entry_Exception extends Exception {}
                            class Invalid_Credentials_Exception extends Exception {}
                            class Mail_Exception extends Exception {}
                            class Account_Activation_Exception extends Exception {}
                            class Email_Does_Not_Exist_Exception extends Exception {}
                            class Invalid_Password_Reset_Exception extends Exception {}
                            class Invalid_Loan_Type_Exception extends Exception {}
                            class Invalid_Bank_Exception extends Exception {}
                            

                            Don't need much more, but the option is available if you wanted to do something more. Also you can extend off your custom exceptions and then have a single catch block to catch the route exception. As for the naming and when to use them, I find it comes naturally. Also just typing "Exce" will cause PhpStorm to bring up the list when needed. You can go crazy and create an exception for everything, or create more general ones. Totally up to you.

                            My autoloader takes care of them:

                            /**
                             * Registers the auto_load function.
                             */
                            spl_autoload_register(function($class_name)
                            {
                                if(substr($class_name, -strlen('Exception')) === 'Exception')
                                {
                                    require('api/Class.Exceptions.php');
                                }
                                else
                                {
                                    require('api/Class.'.$class_name.'.php');
                                }
                            });
                            

                            A real-world example is any example that uses exceptions!

                            Thank you, I appreciate the compliment. I'm not sure my code is dependable per se, but I do my best to make sure all avenues have been accounted for. Sometimes I'll stare at a method and think to myself, "Okay, how can I break this and what can I do to make sure everything is handled nicely?".

                            sneakyimp;11051841 wrote:

                            I agree that we seem to have different perspectives on logging and I think the difference centers on error logging versus just "logging." When you are dealing with stuff that all runs on your own server, it is more reasonable to expect your code to work without errors. When you deal with payment gateways and cloud apis and stuff like that, things start to get messy. Sometimes you can't connect. Sometimes the remote system is down. Sometimes it just barfs when your cron job tries to spin up a server and there's no real explanation of what went wrong and even though you write your cron job to try and shut down servers that won't cooperate, sometimes a cloud server won't shut down for a week because the cloud API has a glitch. Payment gateways are super-messy. They typically have dozens of error codes that might come back, but some I've never actually seen. The full range of responses is really sort of staggering. Cards expire. Accounts get frozen. Sometimes the gateway says a purchase is "on hold" or something, without explaining what that means or how to deal with it. In these cases, I need to log the responses just in case the client says "we are having a problem that comes up every now and then" so I can go actually find what the incoming data looked like. This is why I have severity levels like DEBUG and INFO. These are not error conditions, they are merely extra detail, just in case I need extra detail.

                            To me these are all errors, though. Can't connect, the API has a glitch, it just barfs, etc. Any error code back from the payment gateway (I know Authorize.Net has plenty, especially if you use their AVS) to me is also an error. Unless you get back a positive response, TRUE, or whatever, I consider it to be an error, which I would log of course. Having extra detail is definitely nice, though.

                            sneakyimp;11051841 wrote:

                            To me, a log is somewhere you store information that you need to diagnose and fix problems -- or to better understand how your code functions in a real-life situation.

                            I would probably separate the log to diagnose problems from the log to understand how my code functions.

                            sneakyimp;11051841 wrote:

                            I often use my own logging class to write a log on at least a project-specific basis and more often a project-and-process-specific basis. Looking through a gigantic error log on a complex project is a chore. Having log files broken out by functionality helps you get more quickly to the issue at hand. However, it can be somewhat untidy (and possibly maddening to some) to have a directory full of random log files with widely differing internal formats.

                            I suppose some would find it maddening, but to me it's much better to logically separate things (developers already tend to do this) to make individual browsing and understanding easier.

                              Write a Reply...