Your SlideShare is downloading. ×
0
Error Reporting
in Zend Framework 2

Zend Framework Day – Turin, Italy – 07/02/2014
STEVE MARASPIN
@maraspin
http://www.mvlabs.it/
http://friuli.grusp.org/

5
WHY WORRY?
WE SCREW UP
WE ALL SCREW UP
Application Failures
Application Failures
User Mistakes
INCREASED SUPPORT COST
ABANDONMENT
THE BOTTOM LINE
User Input = Mistake Source
Validation Handling
User Privacy Concerns
• Over 40% of online shoppers are very
concerned over the use of personal
information
• Public opini...
Validation Handling
Improved Error Message
+70% CONVERSIONS
21
Creating A Form in ZF2
<?php
namespace ApplicationForm;
use ZendFormForm;
class ContactForm extends Form
{
public function...
Creating A Form in ZF2
<?php
namespace ApplicationForm;
use ZendFormForm;
class ContactForm extends Form
{
public function...
Adding Form Fields
public function init() {
$this->setName('contact');
$this->setAttribute('method', 'post');
[…]..
$this-...
Adding Form Fields
public function init() {
$this->setName('contact');
$this->setAttribute('method', 'post');
[…]..
$this-...
VALIDATION
Form Validation: InputFilter
Validation: inputFilter
<?php
namespace ApplicationForm;
[…]
class ContactFilter extends InputFilter

{
public function __...
Validation: inputFilter
<?php
namespace ApplicationForm;
[…]
class ContactFilter extends InputFilter

{
public function __...
Required Field Validation
$this->add(array(
'name' => 'email',
'required' => true,
'filters' => array(
array(
'name' => 'S...
Required Field Validation
$this->add(array(
'name' => 'email',
'required' => true,
'filters' => array(
array(
'name' => 'S...
InputFilter Usage
<?php
namespace ApplicationController;

[…]
class IndexController extends AbstractActionController
{

pu...
InputFilter Usage
<?php
namespace ApplicationController;

[…]
class IndexController extends AbstractActionController
{

pu...
Standard Error Message
Improved Error Message
Error Message Customization
$this->add(array(
'name' => 'email',

'required' => true,
'filters' => array(
array('name' => ...
Error Message Customization
$this->add(array(
'name' => 'email',

'required' => true,
'filters' => array(
array('name' => ...
More than we need…
Check Chain
$this->add(array(
'name' => 'email',

'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
)...
Ok, good…
…but, what if?
Words to Avoid

http://uxmovement.com/forms/how-to-make-your-form-error-messages-more-reassuring/
A few tips:
•

•

•

45

Provide the user with a solution to the
problem
Do not use technical jargon, use
terminology that...
Improved message
Condensing N messages into 1
$this->add(array(
'name' => 'email',

'required' => true,
'validators' => array(
array('name'...
Condensing N messages into 1
$this->add(array(
'name' => 'email',

'required' => true,
'validators' => array(
array('name'...
Messages VS message
$this->add(array(
'name' => 'email',

'required' => true,
'validators' => array(
array('name' =>'NotEm...
Translated Error Messages
Default Message Translation
public function onBootstrap(MvcEvent $e)
{
$translator = $e->getApplication()
->getServiceMana...
Custom Message Translation
$this->add(array(
'name' => 'email',
'required' => true,
'validators' => array(
array('name' =>...
Form Factory
$translator = $I_services->get('translator');
$I_form = new Contact();
$I_filter = new ContactFilter($transla...
Translated Error Message
http://patterntap.com/pattern/funny-and-helpful-404-error-page-mintcom
56
Error Display Configuration
Skeleton Applicaton
Configuration
Hiding Exception Traces
'view_manager' => array(

'display_not_found_reason' => false,
'display_exceptions' => false,
'doc...
Hiding Exception Traces
'view_manager' => array(

'display_not_found_reason' => false,
'display_exceptions' => false,
'doc...
Custom Error Pages
'view_manager' => array(

'display_not_found_reason' => false,
'display_exceptions' => false,
'doctype'...
How about PHP Errors?
class IndexController extends AbstractActionController
{
public function indexAction()
{

1/0;
retur...
How about PHP Errors?
class IndexController extends AbstractActionController
{
public function indexAction()
{

1/0;
retur...
Early error detection principle
What can we do?
Handling PHP Errors
public function onBootstrap(MvcEvent $I_e) {
[…]
set_error_handler(array('ApplicationModule','handlePh...
What happens now?
class IndexController extends AbstractActionController
{
public function indexAction()
{

1/0;
return ne...
Now… what if?
class IndexController extends AbstractActionController
{
public function indexAction()
{
$doesNotExist->doSo...
Fatal error: Call to a member function doSomething() on a non-object in
/srv/apps/zfday/module/Application/src/Application...
FATAL ERRORS
Fatal Error Handling
public function onBootstrap(MvcEvent $I_e) {
[…]
$am_config = $I_application->getConfig();
$am_enviro...
Fatal Error Handling
/**
* Redirects user to nice page after fatal has occurred
*/
public static function handleFatalPhpEr...
Fatal Error Handling
'mvlabs_environment' => array(
'exceptions_from_errors' => true,
'recover_from_fatal' => true,
'fatal...
PHP Settings Conf
'mvlabs_environment' => array(
'exceptions_from_errors' => true,
'recover_from_fatal' => true,
'fatal_er...
PHP Settings
public function onBootstrap(MvcEvent $I_e) {
[…]
foreach($am_phpSettings as $key => $value) {
ini_set($key, $...
NICE PAGE!
CUSTOMER SUPPORT TEAM REACTION
http://www.flickr.com/photos/18548283@N00/8030280738
ENVIRONMENT
DEPENDANT
CONFIGURATION
During Deployment
Local/Global Configuration Files
During Deployment
Runtime
Index.php
// Application wide configuration
$am_conf = $am_originalConf = require 'config/application.config.php';

// Env...
application.config.php
'modules' => array(
'Application',
),
Application.dev.config.php
'modules' => array(
'Application',
'ZendDeveloperTools',
),
Enabling Environment Confs
// Application nominal environment
$am_conf = $am_originalConf = require 'config/application.co...
Env Dependant Conf Files
index.php Check
// What environment are we in?
$s_env = getenv('APPLICATION_ENV');
if (empty($s_env)) {
throw new Exceptio...
Apache Config File
<VirtualHost *:80>
DocumentRoot /srv/apps/zfday/public
ServerName www.dev.zfday.it
SetEnv APPLICATION_E...
LOGGING

http://www.flickr.com/photos/otterlove/8154505388/
Why Log?

Troubleshooting
• Stats Generation
• Compliance
•

95
Zend Log
$logger = new ZendLogLogger;
$writer = new ZendLogWriterStream('/var/log/app.log');
$logger->addWriter($writer);
...
Zend Log
$logger = new ZendLogLogger;
$writer = new ZendLogWriterStream('/var/log/app.log');
$logger->addWriter($writer);
...
Writers

98
Writers

99
Logrotate
/var/log/app.log {
missingok
rotate 7
daily
notifempty
copytruncate
compress
endscript
}
100
Writers

101
Writers

102
Writers

103
Zend Log Ecosystem

104
Filter Example
$logger = new ZendLogLogger;
$writer1 = new ZendLogWriterStream('/var/log/app.log');
$logger->addWriter($wr...
Monolog
use MonologLogger;
use MonologHandlerStreamHandler;
$log = new Logger('name');
$log->pushHandler(new StreamHandler...
Monolog Components

107
How to log?
class IndexController {

public function helloAction() {
return new ViewModel('msg' =>"Hello!");

}
}
Traditional Invokation
Logging Within Controller
class GreetingsController {
public function helloAction() {
$I_logger = new Logger();
$I_logger-...
Single Responsability Violation
class GreetingsController {
public function helloAction() {
$I_logger = new Logger();
$I_l...
Fat Controllers
class GreetingsController {

public function helloAction() {
$I_logger = new Logger();
$I_logger->log("We ...
CROSS CUTTING CONCERNS
What can we do?
Handling Events
class Module {
public function onBootstrap(MvcEvent $e) {
$eventManager = $e->getApplication()
->getEventM...
Triggering An Event
class GreetingsController {

public function helloAction() {
$this->eventManager
->trigger('wesaidHell...
Traditional Invokation
Event Manager
OBSERVER
http://www.flickr.com/photos/lstcaress/502606063/
Event Manager
Handling Framework Errors
class Module {
public function onBootstrap(MvcEvent $e) {
$eventManager = $e->getApplication()
-...
Event Manager
Stuff to take home
1.
2.
3.

123

When reporting errors, make sure to be
nice with users
Different error reporting strateg...
2 min intro
https://xkcd.com/208/
Starting Things Up
input { stdin { } }
output { stdout { codec => rubydebug } }
Starting Things Up
input { stdin { } }
output { stdout { codec => rubydebug } }
java -jar logstash-1.3.3-flatjar.jar agent...
Integrated Elasticsearch
input {

file { path => ["/opt/logstash/example.log"] }
}
output {
stdout { codec => rubydebug }
...
Integrated Web Interface
input {

file { path => ["/opt/logstash/example.log"] }
}
output {
stdout { codec => rubydebug }
...
Kibana
Thank you for your attention

Stefano Maraspin
@maraspin
@maraspin
Stefano Maraspin
@maraspin
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Error Reporting in ZF2: form messages, custom error pages, logging
Upcoming SlideShare
Loading in...5
×

Error Reporting in ZF2: form messages, custom error pages, logging

10,479

Published on

Errors frustrate users. No matter if it's their fault or applications', risks that they'll lose interest in our product is high. In this presentation, given at the Italian ZFDay 2014, I discuss about these issues and provide some hints for improving error reporting and handling.

Published in: Technology
1 Comment
17 Likes
Statistics
Notes
No Downloads
Views
Total Views
10,479
On Slideshare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
148
Comments
1
Likes
17
Embeds 0
No embeds

No notes for slide

Transcript of "Error Reporting in ZF2: form messages, custom error pages, logging"

  1. 1. Error Reporting in Zend Framework 2 Zend Framework Day – Turin, Italy – 07/02/2014
  2. 2. STEVE MARASPIN
  3. 3. @maraspin
  4. 4. http://www.mvlabs.it/
  5. 5. http://friuli.grusp.org/ 5
  6. 6. WHY WORRY?
  7. 7. WE SCREW UP
  8. 8. WE ALL SCREW UP
  9. 9. Application Failures
  10. 10. Application Failures User Mistakes
  11. 11. INCREASED SUPPORT COST
  12. 12. ABANDONMENT
  13. 13. THE BOTTOM LINE
  14. 14. User Input = Mistake Source
  15. 15. Validation Handling
  16. 16. User Privacy Concerns • Over 40% of online shoppers are very concerned over the use of personal information • Public opinion polls have revealed a general desire among Internet users to protect their privacy Online Privacy: A Growing Threat. - Business Week, March 20, 2000, 96. Internet Privacy in ECommerce: Framework, Review, and Opportunities for Future Research - Proceedings of the 41st Hawaii International Conference on System Sciences - 2008
  17. 17. Validation Handling
  18. 18. Improved Error Message
  19. 19. +70% CONVERSIONS
  20. 20. 21
  21. 21. Creating A Form in ZF2 <?php namespace ApplicationForm; use ZendFormForm; class ContactForm extends Form { public function __construct() { parent::__construct(); // ... } //... }
  22. 22. Creating A Form in ZF2 <?php namespace ApplicationForm; use ZendFormForm; class ContactForm extends Form { public function __construct() { parent::__construct(); // ... } //... }
  23. 23. Adding Form Fields public function init() { $this->setName('contact'); $this->setAttribute('method', 'post'); […].. $this->add(array('name' => 'email', 'type' => 'text', 'options' => array( 'label' => 'Name', ), ); $this->add(array('name' => 'message', 'type' => 'textarea', 'options' => array( 'label' => 'Message', ), ); //. […].. }
  24. 24. Adding Form Fields public function init() { $this->setName('contact'); $this->setAttribute('method', 'post'); […].. $this->add(array('name' => 'email', 'type' => 'text', 'options' => array( 'label' => 'Name', ), ); $this->add(array('name' => 'message', 'type' => 'textarea', 'options' => array( 'label' => 'Message', ), ); //. […].. }
  25. 25. VALIDATION
  26. 26. Form Validation: InputFilter
  27. 27. Validation: inputFilter <?php namespace ApplicationForm; […] class ContactFilter extends InputFilter { public function __construct() { // filters go here } }
  28. 28. Validation: inputFilter <?php namespace ApplicationForm; […] class ContactFilter extends InputFilter { public function __construct() { // filters go here } }
  29. 29. Required Field Validation $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array( 'name' => 'StringTrim'), ), 'validators' => array( array( 'name' => 'EmailAddress', ) ) ));
  30. 30. Required Field Validation $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array( 'name' => 'StringTrim'), ), 'validators' => array( array( 'name' => 'EmailAddress', ) ) ));
  31. 31. InputFilter Usage <?php namespace ApplicationController; […] class IndexController extends AbstractActionController { public function contactAction() { $form = new Contact(); $filter = new ContactFilter(); $form->setInputFilter($filter); return new ViewModel(array( 'form' => $form ); } }
  32. 32. InputFilter Usage <?php namespace ApplicationController; […] class IndexController extends AbstractActionController { public function contactAction() { $form = new Contact(); $filter = new ContactFilter(); $form->setInputFilter($filter); return new ViewModel(array( 'form' => $form ); } }
  33. 33. Standard Error Message
  34. 34. Improved Error Message
  35. 35. Error Message Customization $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array('name' => 'StringTrim'), ), 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' ), ), ), array('name' => 'EmailAddress'), ) ));
  36. 36. Error Message Customization $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array('name' => 'StringTrim'), ), 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' ), ), ), array('name' => 'EmailAddress'), ) ));
  37. 37. More than we need…
  38. 38. Check Chain $this->add(array( 'name' => 'email', 'required' => true, 'filters' => array( array('name' => 'StringTrim'), ), 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' ), ), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress'), ) ));
  39. 39. Ok, good…
  40. 40. …but, what if?
  41. 41. Words to Avoid http://uxmovement.com/forms/how-to-make-your-form-error-messages-more-reassuring/
  42. 42. A few tips: • • • 45 Provide the user with a solution to the problem Do not use technical jargon, use terminology that your audience understands Avoid uppercase text and exclamation points
  43. 43. Improved message
  44. 44. Condensing N messages into 1 $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' )), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress', 'options' => array( 'message' => 'E-Mail address does not seem to be valid. Please make sure it contains the @ symbol and a valid domain name.', )));
  45. 45. Condensing N messages into 1 $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' )), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress', 'options' => array( 'message' => 'E-Mail address does not seem to be valid. Please make sure it contains the @ symbol and a valid domain name.', )));
  46. 46. Messages VS message $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'messages' => array( NotEmpty::IS_EMPTY => 'We need an '. 'e-mail address to be able to get back to you' )), 'break_chain_on_failure' => true, ), array('name' => 'EmailAddress', 'options' => array( 'message' => 'E-Mail address does not seem to be valid. Please make sure it contains the @ symbol and a valid domain name.', )));
  47. 47. Translated Error Messages
  48. 48. Default Message Translation public function onBootstrap(MvcEvent $e) { $translator = $e->getApplication() ->getServiceManager()->get('translator'); $translator->addTranslationFile( 'phpArray', __DIR__ . '/../../vendor/zendframework/zendframework/'. 'resources/languages/it/Zend_Validate.php', 'default', 'it_IT' ); AbstractValidator::setDefaultTranslator($translator); }
  49. 49. Custom Message Translation $this->add(array( 'name' => 'email', 'required' => true, 'validators' => array( array('name' =>'NotEmpty', 'options' => array( 'translator' => $translator, 'message' => $translator->translate( 'Make sure your e-mail address contains the @ symbol and a valid domain name.' )), 'break_chain_on_failure' => true, ), )));
  50. 50. Form Factory $translator = $I_services->get('translator'); $I_form = new Contact(); $I_filter = new ContactFilter($translator); $I_form->setInputFilter($I_filter); return $I_form;
  51. 51. Translated Error Message
  52. 52. http://patterntap.com/pattern/funny-and-helpful-404-error-page-mintcom
  53. 53. 56
  54. 54. Error Display Configuration Skeleton Applicaton Configuration
  55. 55. Hiding Exception Traces 'view_manager' => array( 'display_not_found_reason' => false, 'display_exceptions' => false, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index'=> __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ), ),
  56. 56. Hiding Exception Traces 'view_manager' => array( 'display_not_found_reason' => false, 'display_exceptions' => false, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index'=> __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ), ),
  57. 57. Custom Error Pages 'view_manager' => array( 'display_not_found_reason' => false, 'display_exceptions' => false, 'doctype' => 'HTML5', 'not_found_template' => 'error/404', 'exception_template' => 'error/index', 'template_map' => array( 'layout/layout' => __DIR__ . '/../view/layout/layout.phtml', 'application/index/index'=> __DIR__ . '/../view/application/index/index.phtml', 'error/404' => __DIR__ . '/../view/error/404.phtml', 'error/index' => __DIR__ . '/../view/error/index.phtml', ), 'template_path_stack' => array( __DIR__ . '/../view', ), ),
  58. 58. How about PHP Errors? class IndexController extends AbstractActionController { public function indexAction() { 1/0; return new ViewModel(); } }
  59. 59. How about PHP Errors? class IndexController extends AbstractActionController { public function indexAction() { 1/0; return new ViewModel(); } }
  60. 60. Early error detection principle
  61. 61. What can we do?
  62. 62. Handling PHP Errors public function onBootstrap(MvcEvent $I_e) { […] set_error_handler(array('ApplicationModule','handlePhpErrors')); } public static function handlePhpErrors($i_type, $s_message, $s_file, $i_line) { if (!($i_type & error_reporting())) { return }; throw new Exception("Error: " . $s_message . " in file " . $s_file . " at line " . $i_line); }
  63. 63. What happens now? class IndexController extends AbstractActionController { public function indexAction() { 1/0; return new ViewModel(); } }
  64. 64. Now… what if? class IndexController extends AbstractActionController { public function indexAction() { $doesNotExist->doSomething(); return new ViewModel(); } }
  65. 65. Fatal error: Call to a member function doSomething() on a non-object in /srv/apps/zfday/module/Application/src/Application/Controller/IndexController.php on line 20
  66. 66. FATAL ERRORS
  67. 67. Fatal Error Handling public function onBootstrap(MvcEvent $I_e) { […] $am_config = $I_application->getConfig(); $am_environmentConf = $am_config['mvlabs_environment']; // Fatal Error Recovery if (array_key_exists('recover_from_fatal', $am_environmentConf) && $am_environmentConf['recover_from_fatal']) { $s_redirectUrl = $am_environmentConf['redirect_url']; } $s_callback = null; if (array_key_exists('fatal_errors_callback', $am_environmentConf)) { $s_callback = $am_environmentConf['fatal_errors_callback']; } register_shutdown_function(array('ApplicationModule', 'handleFatalPhpErrors'), $s_redirectUrl, $s_callback); }
  68. 68. Fatal Error Handling /** * Redirects user to nice page after fatal has occurred */ public static function handleFatalPhpErrors($s_redirectUrl, $s_callback = null) { if (php_sapi_name() != 'cli' && @is_Array($e = @get_last())) { if (null != $s_callback) { // This is the most stuff we can get. // New context outside of framework scope $m_code = isset($e['type']) ? $e['type'] : 0; $s_msg = isset($e['message']) ? $e['message']:''; $s_file = isset($e['file']) ? $e['file'] : ''; $i_line = isset($e['line']) ? $e['line'] : ''; $s_callback($s_msg, $s_file, $i_line); } header("location: ". $s_redirectUrl); } return false; }
  69. 69. Fatal Error Handling 'mvlabs_environment' => array( 'exceptions_from_errors' => true, 'recover_from_fatal' => true, 'fatal_errors_callback' => function($s_msg, $s_file, $s_line) { return false; }, 'redirect_url' => '/error', 'php_settings' => array( 'error_reporting' => E_ALL, 'display_errors' => 'Off', 'display_startup_errors' => 'Off', ), ),
  70. 70. PHP Settings Conf 'mvlabs_environment' => array( 'exceptions_from_errors' => true, 'recover_from_fatal' => true, 'fatal_errors_callback' => function($s_msg, $s_file, $s_line) { return false; }, 'redirect_url' => '/error', 'php_settings' => array( 'error_reporting' => E_ALL, 'display_errors' => 'Off', 'display_startup_errors' => 'Off', ), ),
  71. 71. PHP Settings public function onBootstrap(MvcEvent $I_e) { […] foreach($am_phpSettings as $key => $value) { ini_set($key, $value); } }
  72. 72. NICE PAGE!
  73. 73. CUSTOMER SUPPORT TEAM REACTION http://www.flickr.com/photos/18548283@N00/8030280738
  74. 74. ENVIRONMENT DEPENDANT CONFIGURATION
  75. 75. During Deployment
  76. 76. Local/Global Configuration Files
  77. 77. During Deployment Runtime
  78. 78. Index.php // Application wide configuration $am_conf = $am_originalConf = require 'config/application.config.php'; // Environment specific configuration $s_environmentConfFile = 'config/application.'.$s_env.'.config.php'; if (file_exists($s_environmentConfFile) && is_readable($s_environmentConfFile)) { // Specific environment configuration merge $am_environmentConf = require $s_environmentConfFile; $am_conf = ZendStdlibArrayUtils::merge($am_originalConf, $am_environmentConf ); } // Additional Specific configuration files are also taken into account $am_conf["module_listener_options"]["config_glob_paths"][] = 'config/autoload/{,*.}' . $s_env . '.php'; ZendMvcApplication::init($am_conf)->run();
  79. 79. application.config.php 'modules' => array( 'Application', ),
  80. 80. Application.dev.config.php 'modules' => array( 'Application', 'ZendDeveloperTools', ),
  81. 81. Enabling Environment Confs // Application nominal environment $am_conf = $am_originalConf = require 'config/application.config.php'; // Environment specific configuration $s_environmentConfFile = 'config/application.'.$s_env.'.config.php'; // Do we have a specific configuration file? if (file_exists($s_environmentConfFile) && is_readable($s_environmentConfFile)) { // Specific environment configuration merge $am_environmentConf = require $s_environmentConfFile; $am_conf = ZendStdlibArrayUtils::merge($am_originalConf, $am_environmentConf ); } // Additional Specific configuration files are also taken into account $am_conf["module_listener_options"]["config_glob_paths"][] = 'config/autoload/{,*.}' . $s_env . '.php'; ZendMvcApplication::init($am_conf)->run();
  82. 82. Env Dependant Conf Files
  83. 83. index.php Check // What environment are we in? $s_env = getenv('APPLICATION_ENV'); if (empty($s_env)) { throw new Exception('Environment not set.'. ' Cannot continue. Too risky!'); }
  84. 84. Apache Config File <VirtualHost *:80> DocumentRoot /srv/apps/zfday/public ServerName www.dev.zfday.it SetEnv APPLICATION_ENV "dev" <Directory /srv/apps/zfday/public> AllowOverride FileInfo </Directory> </VirtualHost>
  85. 85. LOGGING http://www.flickr.com/photos/otterlove/8154505388/
  86. 86. Why Log? Troubleshooting • Stats Generation • Compliance • 95
  87. 87. Zend Log $logger = new ZendLogLogger; $writer = new ZendLogWriterStream('/var/log/app.log'); $logger->addWriter($writer); $logger->info('Informational message'); $logger->log(ZendLogLogger::EMERG, 'Emergency message');
  88. 88. Zend Log $logger = new ZendLogLogger; $writer = new ZendLogWriterStream('/var/log/app.log'); $logger->addWriter($writer); $logger->info('Informational message'); $logger->log(ZendLogLogger::EMERG, 'Emergency message'); ZendLogLogger::registerErrorHandler($logger); ZendLogLogger::registerExceptionHandler($logger);
  89. 89. Writers 98
  90. 90. Writers 99
  91. 91. Logrotate /var/log/app.log { missingok rotate 7 daily notifempty copytruncate compress endscript } 100
  92. 92. Writers 101
  93. 93. Writers 102
  94. 94. Writers 103
  95. 95. Zend Log Ecosystem 104
  96. 96. Filter Example $logger = new ZendLogLogger; $writer1 = new ZendLogWriterStream('/var/log/app.log'); $logger->addWriter($writer1); $writer2 = new ZendLogWriterStream('/var/log/err.log'); $logger->addWriter($writer2); $filter = new ZendLogFilterPriority(Logger::CRIT); $writer2->addFilter($filter); $logger->info('Informational message'); $logger->log(ZendLogLogger::CRIT, 'Emergency message');
  97. 97. Monolog use MonologLogger; use MonologHandlerStreamHandler; $log = new Logger('name'); $log->pushHandler(new StreamHandler('/var/log/app.log', Logger::WARNING)); $log->addWarning('Foo'); $log->addError('Bar');
  98. 98. Monolog Components 107
  99. 99. How to log? class IndexController { public function helloAction() { return new ViewModel('msg' =>"Hello!"); } }
  100. 100. Traditional Invokation
  101. 101. Logging Within Controller class GreetingsController { public function helloAction() { $I_logger = new Logger(); $I_logger->log("We just said Hello!"); return new ViewModel('msg' =>"Hello!"); } }
  102. 102. Single Responsability Violation class GreetingsController { public function helloAction() { $I_logger = new Logger(); $I_logger->log("We just said Hello!"); return new ViewModel('msg' =>"Hello!"); } }
  103. 103. Fat Controllers class GreetingsController { public function helloAction() { $I_logger = new Logger(); $I_logger->log("We just said Hello!"); $I_mailer = new Mailer(); $I_mailer->mail($s_msg); $I_queue = new Queue(); $I_queue->add($s_msg); return new ViewModel('msg' =>"Hello!"); } }
  104. 104. CROSS CUTTING CONCERNS
  105. 105. What can we do?
  106. 106. Handling Events class Module { public function onBootstrap(MvcEvent $e) { $eventManager = $e->getApplication() ->getEventManager(); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); $logger = $sm->get('logger'); $eventManager->attach('wesaidHello', function(MvcEvent $event) use ($logger) { $logger->log($event->getMessage()); ); } }
  107. 107. Triggering An Event class GreetingsController { public function helloAction() { $this->eventManager ->trigger('wesaidHello', $this, array('greeting' => 'Hello!') ); return new ViewModel('msg' => "Hello!"); } }
  108. 108. Traditional Invokation
  109. 109. Event Manager
  110. 110. OBSERVER http://www.flickr.com/photos/lstcaress/502606063/
  111. 111. Event Manager
  112. 112. Handling Framework Errors class Module { public function onBootstrap(MvcEvent $e) { $eventManager = $e->getApplication() ->getEventManager(); $moduleRouteListener = new ModuleRouteListener(); $moduleRouteListener->attach($eventManager); $logger = $sm->get('logger'); $eventManager->attach(MvcEvent::EVENT_RENDER_ERROR, function(MvcEvent $e) use ($logger) { $logger->info('An exception has Happened ' . $e->getResult()->exception->getMessage()); }, -200); ); } }
  113. 113. Event Manager
  114. 114. Stuff to take home 1. 2. 3. 123 When reporting errors, make sure to be nice with users Different error reporting strategies could be useful for different environments The event manager reduces coupling and provides flexibility
  115. 115. 2 min intro
  116. 116. https://xkcd.com/208/
  117. 117. Starting Things Up input { stdin { } } output { stdout { codec => rubydebug } }
  118. 118. Starting Things Up input { stdin { } } output { stdout { codec => rubydebug } } java -jar logstash-1.3.3-flatjar.jar agent -f sample.conf
  119. 119. Integrated Elasticsearch input { file { path => ["/opt/logstash/example.log"] } } output { stdout { codec => rubydebug } elasticsearch { embedded => true } } java -jar logstash-1.3.3-flatjar.jar agent -f elastic.conf
  120. 120. Integrated Web Interface input { file { path => ["/opt/logstash/example.log"] } } output { stdout { codec => rubydebug } elasticsearch { embedded => true } } java -jar logstash.jar agent -f elastic.conf --web
  121. 121. Kibana
  122. 122. Thank you for your attention Stefano Maraspin @maraspin
  123. 123. @maraspin
  124. 124. Stefano Maraspin @maraspin
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×