Warning: file(): https:// wrapper is disabled in the server configuration by allow_url_fopen=0 in /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php on line 40

Warning: file(https://scipilot.org/blog/wp-content/plugins/ap-extended-mime-types/mime-types.txt): failed to open stream: no suitable wrapper could be found in /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php on line 40

Warning: Invalid argument supplied for foreach() in /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php on line 42

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909

Warning: Cannot modify header information - headers already sent by (output started at /home/sciptorg/public_html/blog/wp-content/plugins/ap-extended-mime-types/ap-extended-mime-types.php:40) in /home/sciptorg/public_html/blog/wp-includes/rest-api/class-wp-rest-server.php on line 1909
{"id":192,"date":"2015-01-04T22:33:25","date_gmt":"2015-01-04T11:33:25","guid":{"rendered":"http:\/\/scipilot.org\/blog\/?p=192"},"modified":"2015-01-06T18:19:21","modified_gmt":"2015-01-06T07:19:21","slug":"pulse-apm","status":"publish","type":"post","link":"https:\/\/scipilot.org\/blog\/2015\/01\/04\/pulse-apm\/","title":{"rendered":"Pulse APM"},"content":{"rendered":"

Pulse – Application Heartbeat Monitor<\/h1>\n

Pulse is a new library I\u00a0wrote\u00a0in a weekend because I couldn’t find anything out there which performs this simple service. And I was tired of getting calls from GoGet on my day off (from my job as CTO of Fleetcutter).<\/p>\n

I\u00a0needed to monitor a somewhat fragile, legacy Windows application server\u00a0which already had a heartbeat database record it updates every minute. Great, but nothing was monitoring the heartbeat record, so no cigar there. I also have a bunch of other servers written in different languages hosted on different platforms. I also have a few\u00a0separate support companies (customer service, managed hosting and 24-hr IT support and application triage) so I’d like to notify each\u00a0of\u00a0specific\u00a0levels\/types of problems, and each has their own management infrastructure and contact preferences.<\/p>\n

Therefore I wanted something that was simple\u00a0and\u00a0reliable but extendable and flexible.<\/p>\n

So I wrote Pulse:\u00a0https:\/\/bitbucket.org\/scipilot\/pulse<\/a><\/p>\n

I believe the architecture is a good example of Dependency Injection, the Strategy Pattern, the Repository Pattern, IoC Container (flexible), and automated testing (reliable). In fact, during initial development I wrote all the interfaces first, then the test platform, then began to fill in the functionality while writing the tests, in a loose form of TDD. I like the idea that the code was initially run solely via the test platform (i.e. no dummy manually run top-level-scripts). This meant that when I eventually deployed the system it pretty much worked first time! The main issues discovered on deployment were (apart from one major foobar) deployment-related things like the autoload location and the need\u00a0to ‘park’ work-in-progress configurations.<\/p>\n

In fact, in its first day of operation it caught a major outage seconds after the cause and several minutes before any humans noticed. But… I ignored the notification emails thinking they were false positives!<\/p>\n

But now I’m out of the loop, I’m fully off-duty on an island in the Indian Ocean.\u00a0Now my 24hr support has a\u00a0new\u00a0pair of ears stethoscoped directly into the butterflies that beat in the heart of our\u00a0veteran application.<\/p>\n

Overview<\/h2>\n

Pulse is a standalone component which provides simple application\/service heartbeat monitoring.<\/p>\n

Simply put: it checks your application is still alive<\/em>.<\/p>\n

    \n
  1. A timestamp is updated by your service or the daemon, and a monitor daemon regularly checks the hearbeats are current.<\/li>\n
  2. If a service fails to register a heartbeat within the configured thresholds, notifications are triggered.<\/li>\n<\/ol>\n

    Client service\/applications can have one or multiple heartbeats monitored – called Pulses.<\/p>\n

    All components are customisable: notifiers, config, log, storage (via dependency-injection in an IoC container). The notifications are the most likely to need customisation, e.g. sending alerts to your own dashboard API. If you customised the storage engine, you could perhaps integrate saving heatbeats from another source.<\/p>\n

    e.g. 1 – Integrated Application Heartbeat Update and Monitor Service Sending Email Notifications<\/h3>\n

    This example shows a PHP application using the Pulse class to store regular heatbeats. The monitor service is using the email notifier and regularly checks the heartbeat database.<\/p>\n

    \"example<\/p>\n

    Note if the heartbeat database is a simple file (serialised, sqlite) then the monitor service would need to be installed locally.<\/p>\n

    e.g. 2 – Multiple Application Heartbeats and Multiple Notification Types<\/h3>\n

    This example demonstrates scaling the application to monitor multiple applications and use different notification strategies to send different levels of alerts, or notificiations from the different applications, to different support staff.<\/p>\n

    \"example<\/p>\n

    e.g. 3 – Remote Probe Ability for Legacy or non-PHP Apps<\/h3>\n

    This example shows the Probe<\/code> feature querying a remote application’s status, without integrating into it.<\/p>\n

    \"example<\/p>\n

    Alarms<\/h2>\n

    There are three states your service can be in:<\/p>\n

      \n
    1. OK – All is well. Nothing to report.<\/li>\n
    2. ALERT – Service degraded. Things are getting bumpy, but you might not want to call out the troops yet…<\/li>\n
    3. ALARM – System down. Urgent panic, wake up the boss.<\/li>\n
    4. OK again – on returning to normal you will get one notification.<\/li>\n<\/ol>\n

      You only get a notification when the service changes state<\/em>.<\/p>\n

      You don’t have to use the ALERT state, but it gives you a bit of extra granularity to triage any flapping. Often a system will have a ‘grey area’ where you don’t want to really panic everyone, but perhaps you should keep an eye on things. This ALERT state can therefore be targetted at a different response team (see below).<\/p>\n

      Installation<\/h2>\n

      Standard composer installation:<\/p>\n

      \n
      ><\/span> composer<\/span> require<\/span> scipilot<\/span>\/<\/span>pulse<\/span>\r\n<\/pre>\n<\/div>\n

      or more likely you will fork it and require your own.<\/p>\n

      Usage<\/h2>\n

      There are two halves to the system:<\/p>\n

      1. Heatbeat Update<\/h3>\n

      This can be done in one of two ways:<\/p>\n

      a) “Locally”: Each service can require the component and call Pulse->beat() regularly. Of course this only works for PHP services, and ones you can modify by integrating with this component.<\/p>\n

      b) “Remotely”: The Pulse daemon can poll your system using “Scopes” to update the heartbeats. This is the most unintrusive method, and can interface with existing database timetamps for example.<\/p>\n

      Scope<\/code>s allow you to implement custom probes into other systems to extract heartbeats. Currently there is only one: a DatabaseRecordScope which queries an SQL DB for a single timestamp.<\/p>\n

      The IoC model allows you to easily implement another interface to query an API, top, PID file etc.<\/p>\n

      2. Pulse Monitoring<\/h3>\n

      The monitoring daemon must be run in a supervised process (or it can be polled by your own scheduler).<\/p>\n

      Both uses obviously must share the same config, by default these are files in the storage<\/code> folder, so the same installation must be used. If you need to separate the daemon from your services, you would need to implement another Storage<\/code> strategy (i.e. implement a Storage<\/code> class and inject into a modified container).<\/p>\n

      Usage Examples<\/h3>\n

      See \/bin\/example_service.php<\/code> and \/bin\/daemon.php<\/code> respectively.<\/p>\n

        \n
      1. Copy the sample config to config.json<\/li>\n
      2. Edit your email address in the default ‘to’.<\/li>\n
      3. Run php \/bin\/daemon.php &; php \/bin\/example_service.php &<\/code><\/li>\n
      4. Check your inbox!<\/li>\n<\/ol>\n

        Also see the Unit Tests for usages (although I’ve always hated reading people say that).<\/p>\n

        Config<\/h2>\n

        Each Pulse<\/code> is configured with alert and alarm thresholds, friendly name, unique ID.<\/p>\n

        Notifications also require some configuration too (see below).<\/p>\n

        See storage\/config-SAMPLE.json<\/code> for a bootstrap config.<\/p>\n

        You can either hand-craft a json config file, or programmatically create Pulse<\/code> or Scope<\/code> objects, which can persist their own configuration for re-load later. See the PulseRegistry<\/code> and ScopeRegistry<\/code>.<\/p>\n

        Notifications<\/h2>\n

        Email Notifications<\/h3>\n

        Initially there is only an EmailNotify<\/code> implementation. it requires the following configuration:<\/p>\n

        \n
        notify<\/span>.<\/span>EmailNotify<\/span>.<\/span>default<\/span>.<\/span>email<\/span>.<\/span>to<\/span>\r\nnotify<\/span>.<\/span>EmailNotify<\/span>.<\/span>default<\/span>.<\/span>email<\/span>.<\/span>subject<\/span>            -<\/span> default<\/span> subject<\/span>\r\nnotify<\/span>.<\/span>EmailNotify<\/span>.<\/span>default<\/span>.<\/span>email<\/span>.<\/span>body<\/span>               -<\/span> with<\/span> placeholders:<\/span> _TYPE_<\/span>,<\/span> _LEVEL_<\/span>,<\/span> _NAME_<\/span>,<\/span> _MESSAGE_<\/span>\r\n<\/pre>\n<\/div>\n

        Body template e.g.:<\/p>\n

        \n
        \"Heads up! Alert type: _TYPE_, at level: _LEVEL_, was received for service _NAME_. \\n Details are as follows: _MESSAGE_\"<\/span>\r\n<\/pre>\n<\/div>\n

        Optionally you can customise any specific messages for both monitoring alerts, and internal errors:<\/p>\n

        \n
        notify<\/span>.<\/span>EmailNotify<\/span>.<<\/span>TYPE<\/span>>.<<\/span>LEVEL<\/span>>.<\/span>email<\/span>.<\/span>to<\/span>          -<\/span> specific<\/span> alert<\/span> overrides<\/span>\r\nnotify<\/span>.<\/span>EmailNotify<\/span>.<<\/span>TYPE<\/span>>.<<\/span>LEVEL<\/span>>.<\/span>email<\/span>.<\/span>subject<\/span>\r\nnotify<\/span>.<\/span>EmailNotify<\/span>.<<\/span>TYPE<\/span>>.<<\/span>LEVEL<\/span>>.<\/span>email<\/span>.<\/span>body<\/span>        -<\/span> with<\/span> placeholders:<\/span> _TYPE_<\/span>,<\/span> _LEVEL_<\/span>,<\/span> _MESSAGE_<\/span>\r\n<\/pre>\n<\/div>\n

        e.g. you might want outage alarms sent to L1 Support pagers, but internal warnings sent to developers or devops.<\/p>\n

        See ‘INotify’ for these constants.<\/p>\n

        Logs<\/h2>\n

        The system logs INFO by default into the storage<\/code> folder.<\/p>\n

        This will just be service status changes<\/em>, and any system errors (e.g. notification send failures). They will be pretty small (if your services are stable), but you might want to rotate them anyway.<\/p>\n

        You can change the level of detail up to debug or down to just warnings, by calling app->log->setVerbosity()<\/code>. (There is no config option for this, at present)<\/p>\n

        Architecture<\/h2>\n
        \n
        -<\/span> IoC<\/span> App<\/span> Container<\/span>\r\n    -<\/span> Config<\/span> DI<\/span>\r\n    -<\/span> Log<\/span> DI<\/span>\r\n    -<\/span> Storage<\/span> DI<\/span>\r\n    -<\/span> Notification<\/span> DI<\/span>\r\n-<\/span> PulseRegistry<\/span>\r\n    -<\/span> Pulse<\/span>-><\/span>beat<\/span>\r\n-<\/span> ScopeRegistry<\/span>\r\n    -<\/span> Scope<\/span>-><\/span>Listen<\/span>\r\n-<\/span> Monitor<\/span> Daemon<\/span>-><\/span>run:<\/span>\r\n    -<\/span> Listen<\/span> to<\/span> Scopes<\/span>\r\n    -<\/span> Scan<\/span> Pulses<\/span>\r\n-<\/span> Feed<\/span> API<\/span> (<\/span>TODO!<\/span>)<\/span>\r\n<\/pre>\n<\/div>\n

        The Feed API has not yet been implemented. The idea is to allow remote applications both register Beats, and fetch Pulse status.<\/p><\/blockquote>\n

        Roadmap<\/h3>\n