ninenines/cowboy — pull request #750 by fishcakez (2014-10-03 16:39:47+00:00)
Title: Add full support for sys module (debug cowboy process state)

This change provides support for the `sys` module in cowboy processes. Where possible new callbacks are as similar to existing OTP behaviours as possible. This changes requires 17.0 so can only be merged into the `2.0` branch, and not `1.0`.

To use the debugging features added here you an use `sys`, `observer`, `recon` or OTP debugging tool of choice as if the cowboy processes were using the built in OTP behaviours.

Basic HTTP handlers have two new optional callbacks:
```erlang
-callback code_change(any(), cowboy_req:req(), any(), any()) -> {ok, cowboy_req:req(), any()}.

-callback format_status(normal | terminate, [[{any(), any()}], cowboy_req:req(), any()]) -> any().
```

Middlewares and sub protocols have the following possible return values:
* `{ok, Req, Env}`
* `{suspend, Module, Function, Args}`
* `{system, From, Msg, Module, Req, Env, Misc}`
* `{halt, Req, Env}`

Notice the new `system` callback and the addition of `Env` in the `halt` return value.

The `system` return value is used to handle system messages. The `Module` used must implement the `cowboy_system` callbacks. These are as close as possible to `system_*` callbacks as possible:
```erlang
-callback continue(cowboy_req:req(), cowboy_middleware:env(), any())
-> {ok, cowboy_req:req(), cowboy_middleware:env()}
| {suspend, module(), atom(), [any()]}
| {system, {pid(), term()}, any(), module(), cowboy_req:req(), cowboy_middleware:env(), any()}
| {halt, cowboy_req:req(), cowboy_middleware:env()}.

-callback terminate(any(), cowboy_req:req(), cowboy_middleware:env(), any()) -> no_return().

-callback code_change(cowboy_req:req(), any(), module(), any(), any()) -> {ok, cowboy_req:req(), any()}.
```

And may implement the three optional callbacks (again similar to the `system_*` callbacks):
```erlang
-callback get_state(cowboy_req:req(), any()) -> {ok, {module(), cowboy_req:req(), any()}}.

-callback replace_state(replace_state(), cowboy_req:req(), any()) ->
{ok, {module(), cowboy_req:req(), any()}, cowboy_req:req(), any()}.

-callback format_status(normal, [[{any(), any()}] |
running | suspended | cowboy_req:req() | cowboy_middleware:env() | any()])
-> any().
```

A requirement of supporting the `sys` module is using `proc_lib`. This has the following side effects:
* A `crash_report` is sent to the error logger on abnormal exit
* The emulator will nolonger send an error logger on uncaught error
* Uncaught errors will nolonger have a stacktrace in the exit signal

I will add more to the guide once the API has been finalised/confirmed.