Clean up debugging documentation

This commit is contained in:
Will Rossiter 2014-10-13 21:52:19 +13:00 committed by Cam Findlay
parent fc952ef1e8
commit ebf28bc66b
9 changed files with 171 additions and 253 deletions

View File

@ -0,0 +1,88 @@
title: Environment Types
summary: Configure your SilverStripe environment to define how your web application behaves.
# Environment Types
SilverStripe knows three different environment types (or "modes"). Each of the modes gives you different tools
and behaviors. The environment is managed either through a [YML configuration file](../configuration) or in a
[environment configuration file](../../getting_started/environment_management).
The definition of setting an environment type in a `mysite/_config/app.yml` looks like
:::yml
Director:
environment_type: 'dev'
The definition of setting an environment type in a `_ss_environment.php` file looks like
:::php
define('SS_ENVIRONMENT_TYPE', 'dev');
The three environment types you can set are `dev`, `test` and `live`.
### Dev
When developing your websites, adding page types or installing modules you should run your site in `dev`. In this mode
you will see full error back traces and view the development tools without having to be logged in as an administrator
user.
<div class="alert" markdown="1">
**dev mode should not be enabled long term on live sites for security reasons**. In dev mode by outputting back traces
of function calls a hacker can gain information about your environment (including passwords) so you should use dev mode
on a public server very carefully.
</div>
### Test Mode
Test mode is designed for staging environments or other private collaboration sites before deploying a site live.
In this mode error messages are hidden from the user and SilverStripe includes `[api:BasicAuth]` integration if you
want to password protect the site. You can enable that but adding this to your `mysite/_config/app.yml` file:
:::yml
---
Only:
environment: 'test'
---
BasicAuth:
entire_site_protected: true
### Live Mode
All error messages are suppressed from the user and the application is in it's most *secure* state.
<div class="alert">
Live sites should always run in live mode. You should not run production websites in dev mode.
</div>
## Checking Environment Type
You can check for the current environment type in [config files](../configuration) through the `environment` variant.
**mysite/_config/app.yml**
---
Only:
environment: 'live'
---
MyClass:
myvar: live_value
---
Only:
environment: 'test'
---
MyClass:
myvar: test_value
Checking for what environment you're running in can also be done in PHP. Your application code may disable or enable
certain functionality depending on the environment type.
:::php
if(Director::isLive()) {
// is in live
} else if(Director::isTest()) {
// is in test mode
} else if(Director::isDev()) {
// is in dev mode
}

View File

@ -1,23 +1,29 @@
title: Error Handling
summary: Trap, fire and report user exceptions, warnings and errors.
# Error Handling
SilverStripe has its own error trapping and handling support.
SilverStripe has its own error trapping and handling support. On development sites, SilverStripe will deal harshly with
any warnings or errors: a full call-stack is shown and execution stops for anything, giving you early warning of a
potential issue to handle.
## Triggering the error handler.
You should use [user_error](http://www.php.net/user_error) to throw errors where appropriate.
:::php
if(true == false) {
user_error("I have an error problem", E_USER_ERROR);
}
if(0 / 0) {
user_error("This time I am warning you", E_USER_WARNING);
}
## Error Levels
SilverStripe recognises two basic levels of error:
* **WARNING:** Something strange has happened; the system has attempted to continue as best it can, but the developers
need to look at this. This category also include areas where a newer version of SilverStripe requires changes to the
site's customised code.
* **FATAL ERROR:** There is no way that the system can attempt to continue with the particular operation; it would be
dangerous to report success to the user.
You should use [user_error](http://www.php.net/user_error) to throw errors where appropriate. The more information we
have about what's not right in the system, the better we can make the application.
* **E_USER_WARNING:** Err on the side of over-reporting warnings. The more warnings we have, the less chance there is
of a developer leaving a bug. Throwing warnings provides a means of ensuring that developers know whow
* **E_USER_WARNING:** Err on the side of over-reporting warnings. Throwing warnings provides a means of ensuring that
developers know:
* Deprecated functions / usage patterns
* Strange data formats
* Things that will prevent an internal function from continuing. Throw a warning and return null.
@ -25,63 +31,43 @@ of a developer leaving a bug. Throwing warnings provides a means of ensuring th
* **E_USER_ERROR:** Throwing one of these errors is going to take down the production site. So you should only throw
E_USER_ERROR if it's going to be **dangerous** or **impossible** to continue with the request.
Note that currently, the SilverStripe core doesn't follow these standards perfectly.
* Right now, **every** failed SQL statement throws a fatal error. Many 'select' queries could probably be reduced to
warnings.
* A lot of assertion checking in the system that throws errors when it should throw warnings.
## Friendly Website Errors
An HTTP 500 error will be sent when there has been a fatal error on either a test or production site. You can make this
friendlier - much like the 404 page, the error content can be edited within the CMS.
* Create a page of type `[api:ErrorPage]`
* Set the error code to 500
* Publish the page.
**HOW IT WORKS: **The publication script for `[api:ErrorPage]` will write the full HTML content, including the template styling,
to assets/error-500.html. The fatal error handler looks for the presence of this file, and if it exists, dumps the
content. This means that database access isn't required to provide a 500 error page.
## Filesystem Logs
You can indicate a log file relative to the site root.
### From SilverStripe
You can indicate a log file relative to the site root. The named file will have a terse log sent to it, and the full log
(an encoded file containing backtraces and things) will go to a file of a similar name, but with the suffix ".full"
added.
`mysite/_config.php`:
**mysite/_config.php**
:::php
// log errors and warnings
SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::WARN, '<=');
// or just errors
SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::ERR);
if(!Director::isDev()) {
// log errors and warnings
SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::WARN, '<=');
### From PHP
In addition to SilverStripe-integrated logging, it is adviseable to fall back to PHPs native logging functionality. A
script might terminate before it reaches the SilverStripe errorhandling, for example in the case of a fatal error.
`mysite/_config.php`:
:::php
ini_set("log_errors", "On");
ini_set("error_log", "/my/logfile/path");
// or just errors
SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::ERR);
}
<div class="info" markdown="1">
In addition to SilverStripe-integrated logging, it is advisable to fall back to PHPs native logging functionality. A
script might terminate before it reaches the SilverStripe error handling, for example in the case of a fatal error. Make
sure `log_errors` and `error_log` in your PHP ini file are configured.
</div>
## Email Logs
You can send both fatal errors and warnings in your code to a specified email-address.
`mysite/_config.php`:
**mysite/_config.php**
:::php
// log errors and warnings
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::WARN, '<=');
// or just errors
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::ERR);
if(!Director::isDev()) {
// log errors and warnings
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::WARN, '<=');
// or just errors
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::ERR);
}
## API Documentation
* [api:SS_Log]

View File

@ -2,152 +2,33 @@ summary: Learn how to identify errors in your application and best practice for
# Debugging
## Environment Types
SilverStripe can be a large and complex framework to debug, but there are ways to make debugging less painful. In this
guide we show the basics on defining the correct [Environment Type](environment_type) for your application and other
built-in helpers for dealing with application errors.
Silverstripe knows three different environment-types (or "debug-levels"). Each of the levels gives you different tools
and functionality. "dev", "test" and "live". You can either configure the environment of the site in your
[config.yml file](/topics/configuration) or in your [environment configuration file](/topics/environment-management).
[CHILDREN]
The definition of setting an environment in your `config.yml` looks like
## Performance
:::yml
Director:
environment_type: 'dev'
See the [Profiling](../performance/profiling) documentation for more information on profiling SilverStripe to track down
bottle-necks and identify slow moving parts of your application chain.
### Dev Mode
## Debugging Utilities
When developing your websites, adding page types or installing modules you should run your site in devmode. In this mode
you will be able to view full error backtraces and view the development tools without logging in as admin.
To set your site to dev mode set this in your `config.yml` file
:::yml
Director:
environment_type: 'dev'
Please note **devmode should not be enabled long term on live sites for security reasons**. In devmode by outputting
backtraces of function calls a hacker can gain information about your environment (including passwords) so you should
use devmode on a public server very very carefully
### Test Mode
Test mode is designed for staging environments or other private collaboration sites before deploying a site live. You do
not need to use test mode if you do not have a staging environment or a place for testing which is on a public server)
In this mode error messages are hidden from the user and it includes `[api:BasicAuth]` integration if you want to password
protect the site.
To set your site to test mode set this in your `config.yml` file
:::yml
Director:
environment_type: 'test'
A common situation is to enable password protected site viewing on your test site only.
You can enable that but adding this to your `config.yml` file:
:::yml
---
Only:
environment: 'test'
---
BasicAuth:
entire_site_protected: true
### Live Mode
Live sites should always run in live mode. Error messages are suppressed from the user but can be optionally configured
to email the developers. This enables near real time reporting of any fatal errors or warnings on the site and can help
find any bugs users run into.
To set your site to live mode set this in your `config.yml` file
:::yml
Director:
environment_type: 'live'
### Checking Environment Types
You can check for the current environment type in [config files](/topics/configuration) through the "environment" variant.
This is useful for example when you have various API keys on your site and separate ones for dev / live or for configuring
environment settings based on type .
---
Only:
environment: 'test'
---
MyClass:
myvar: myval
In addition, you can use the following methods in PHP code:
The [api:Debug] class contains a number of static utility methods for more advanced debugging.
:::php
Director::isDev();
Director::isTest();
Director::isLive();
Debug::show($myVariable);
// similar to print_r($myVariable) but shows it in a more useful format.
## Email Errors
Debug::message("Wow, that's great");
// prints a short debugging message.
:::yml
Debug:
send_errors_to: 'your@email.com'
SS_Backtrace::backtrace();
// prints a calls-stack
## Customizing Error-Output
## API Documentation
You can customize "friendly error messages" in test/live-mode by creating *assets/error-500.html*.
## URL Variable Tools
You can get lots of information on the current rendering context without writing any code or launching a debugger: Just
attach some [Debug Parameters](/reference/urlvariabletools) to your current URL to see the compiled template, or all performed
SQL-queries.
## Debugging methods
The Debug class contains a number of static methods
* *Debug::show($myVariable)*: performs a kind of *print_r($myVariable)*, but shows it in a more useful format.
* *Debug::message("Wow, that's great")*: prints a short debugging message.
* *SS_Backtrace::backtrace()*: prints a calls-stack
### Error handling
On development sites, we deal harshly with any warnings or errors: a full call-stack is shown and execution stops. This
is basically so that we deal with them promptly, since most warnings are indication that **something** is broken.
On live sites, all errors are emailed to the address specified in the `Debug.send_errors_to` config setting.
### Debugging techniques
Since we don't have a decent interactive debugger going, we use the following debugging techniques:
* Putting *Debug::show()* and *Debug::message()* at key places in the code can help you know what's going on.
Sometimes, it helps to put this debugging information into the core modules, although, if possible, try and get what you
need by using [url querystring variables](/reference/urlvariabletools).
* Calling *user_error("breakpoint", E_USER_ERROR)* will kill execution at that point and give you a call stack to see
where you came from. Alternatively, *SS_Backtrace::backtrace()* gives you similar information without killing
execution.
* There are some special [url querystring variables](/reference/urlvariabletools) that can be helpful in seeing what's going on
with core modules, such as the templates.
* You can also use *$Debug* with *ViewableData* in templates.
#### Unit Testing
A good way to avoid writing the same test stubs and var_dump() commands over and over again is to codify them as [unit
tests](testing-guide). This way you integrate the debugging process right into your quality control, and eventually in
the development effort itself as "test-driven development".
#### Profiling
Profiling is the best way to identify bottle necks and other slow moving parts of your application prime for optimization. SilverStripe
does not include any profiling tools out of the box, but we recommend the use of existing tools such as [XHProf](https://github.com/facebook/xhprof/)
and [XDebug](http://xdebug.org/).
* [Profiling with XHProf](http://techportal.inviqa.com/2009/12/01/profiling-with-xhprof/)
* [Profiling PHP Applications With xdebug](http://devzone.zend.com/1139/profiling-php-applications-with-xdebug/)
* [api:SS_Log]
* [api:SS_Backtrace]
* [api:Debug]

View File

@ -0,0 +1,8 @@
#### Profiling
Profiling is the best way to identify bottle necks and other slow moving parts of your application prime for optimization. SilverStripe
does not include any profiling tools out of the box, but we recommend the use of existing tools such as [XHProf](https://github.com/facebook/xhprof/)
and [XDebug](http://xdebug.org/).
* [Profiling with XHProf](http://techportal.inviqa.com/2009/12/01/profiling-with-xhprof/)
* [Profiling PHP Applications With xdebug](http://devzone.zend.com/1139/profiling-php-applications-with-xdebug/)

View File

@ -1,52 +0,0 @@
# Howto: Track Member Logins
Sometimes its good to know how active your users are,
and when they last visited the site (and logged on).
A simple `LastVisited` property on the `Member` record
with some hooks into the login process can achieve this.
In addition, a `NumVisit` property will tell us how
often the member has visited. Or more specifically,
how often he has started a browser session, either through
explicitly logging in or by invoking the "remember me" functionality.
:::php
<?php
class MyMemberExtension extends DataExtension {
private static $db = array(
'LastVisited' => 'Datetime',
'NumVisit' => 'Int',
);
public function memberLoggedIn() {
$this->logVisit();
}
public function memberAutoLoggedIn() {
$this->logVisit();
}
public function updateCMSFields(FieldList $fields) {
$fields->addFieldsToTab('Root.Main', array(
ReadonlyField::create('LastVisited', 'Last visited'),
ReadonlyField::create('NumVisits', 'Number of visits')
));
}
protected function logVisit() {
if(!Security::database_is_ready()) return;
DB::query(sprintf(
'UPDATE "Member" SET "LastVisited" = %s, "NumVisit" = "NumVisit" + 1 WHERE "ID" = %d',
DB::getConn()->now(),
$this->owner->ID
));
}
}
Now you just need to apply this extension through your config:
:::yml
Member:
extensions:
- MyMemberExtension

View File

@ -1,7 +1,12 @@
summary: This guide covers user authentication, the permission system and how to secure your code against malicious behaviors
[CHILDREN]
# Security and User Authentication
## How-to
This guide covers using and extending the user authentication in SilverStripe, permissions, user groups and roles, and
how to secure your code against malicious behaviors of both your users and hackers.
[CHILDREN How_To]
[CHILDREN Exclude=How_to]
## How to's
[CHILDREN Folder=How_To]