Skip to content

Add an HTTP(S) driver #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ It doesn't require any modification to your application's code and let's you col
1. `$ git clone https://github.com/patrickallaert/php-apm.git`
2. `$ cd php-apm`
3. `$ phpize`
4. Configure the extension, by default, **sqlite3**, **MariaDB/MySQL**, **[StatsD](https://github.com/etsy/statsd/)** and **Socket** support are enabled:
4. Configure the extension, by default, **sqlite3**, **MariaDB/MySQL**, **[StatsD](https://github.com/etsy/statsd/)**, **HTTP**, and **Socket** support are enabled:

```
$ ./configure [--with-sqlite3[=DIR]] [--with-mysql[=DIR]] [--enable-statsd] [--enable-socket] [--with-debugfile[=FILE]]
$ ./configure [--with-sqlite3[=DIR]] [--with-mysql[=DIR]] [--enable-statsd] [--enable-socket] [--enable-http] [--with-debugfile[=FILE]]
```
To disable the support of a `--with-*` switch, use: `--without-*`, example: `$ ./configure --without-sqlite3`
To disable the support of a `--enable-*` switch, use: `--disable-*`, example: `$ ./configure --disable-socket`
Expand Down
25 changes: 25 additions & 0 deletions apm.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
#ifdef APM_DRIVER_SOCKET
# include "driver_socket.h"
#endif
#ifdef APM_DRIVER_HTTP
#include "driver_http.h"
#endif

ZEND_DECLARE_MODULE_GLOBALS(apm);
static PHP_GINIT_FUNCTION(apm);
Expand Down Expand Up @@ -240,6 +243,25 @@ PHP_INI_BEGIN()
/* process silenced events? */
STD_PHP_INI_BOOLEAN("apm.socket_process_silenced_events", "1", PHP_INI_PERDIR, OnUpdateBool, socket_process_silenced_events, zend_apm_globals, apm_globals)
#endif

#ifdef APM_DRIVER_HTTP
/* Boolean controlling whether the driver is active or not */
STD_PHP_INI_BOOLEAN("apm.http_enabled", "1", PHP_INI_ALL, OnUpdateBool, http_enabled, zend_apm_globals, apm_globals)
/* Boolean controlling the collection of stats */
STD_PHP_INI_BOOLEAN("apm.http_stats_enabled", "1", PHP_INI_ALL, OnUpdateBool, http_stats_enabled, zend_apm_globals, apm_globals)
/* Control which exceptions to collect (0: none exceptions collected, 1: collect uncaught exceptions (default), 2: collect ALL exceptions) */
STD_PHP_INI_ENTRY("apm.http_exception_mode","1", PHP_INI_PERDIR, OnUpdateLongGEZero, http_exception_mode, zend_apm_globals, apm_globals)
/* error_reporting of the driver */
STD_PHP_INI_ENTRY("apm.http_error_reporting", NULL, PHP_INI_ALL, OnUpdateAPMhttpErrorReporting, http_error_reporting, zend_apm_globals, apm_globals)
/* process silenced events? */
STD_PHP_INI_BOOLEAN("apm.http_process_silenced_events", "1", PHP_INI_PERDIR, OnUpdateBool, http_process_silenced_events, zend_apm_globals, apm_globals)
STD_PHP_INI_ENTRY("apm.http_request_timeout", "1000", PHP_INI_ALL, OnUpdateLong, http_request_timeout, zend_apm_globals, apm_globals)
STD_PHP_INI_ENTRY("apm.http_server", "http://localhost", PHP_INI_ALL, OnUpdateString, http_server, zend_apm_globals, apm_globals)
STD_PHP_INI_ENTRY("apm.http_client_certificate", NULL, PHP_INI_ALL, OnUpdateString, http_client_certificate, zend_apm_globals, apm_globals)
STD_PHP_INI_ENTRY("apm.http_client_key", NULL, PHP_INI_ALL, OnUpdateString, http_client_key, zend_apm_globals, apm_globals)
STD_PHP_INI_ENTRY("apm.http_certificate_authorities", NULL, PHP_INI_ALL, OnUpdateString, http_certificate_authorities, zend_apm_globals, apm_globals)
STD_PHP_INI_ENTRY("apm.http_max_backtrace_length", "0", PHP_INI_ALL, OnUpdateLong, http_max_backtrace_length, zend_apm_globals, apm_globals)
#endif
PHP_INI_END()

static PHP_GINIT_FUNCTION(apm)
Expand Down Expand Up @@ -272,6 +294,9 @@ static PHP_GINIT_FUNCTION(apm)
*next = apm_driver_socket_create();
next = &(*next)->next;
#endif
#ifdef APM_DRIVER_HTTP
*next = apm_driver_http_create();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the pattern would be to include next = &(*next)->next; with the HTTP driver, static analysis doesn't like assignment to an unused variable.

#endif
}

static void recursive_free_driver(apm_driver_entry **driver)
Expand Down
23 changes: 23 additions & 0 deletions apm.ini
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,26 @@ extension=apm.so
; Socket path (accept multiple entries, separated by "|", prefixed with "file:" or "tcp:")
; Example: apm.socket_path=file:/var/tmp/apm.sock|tcp:localhost:1234
; apm.socket_path=file:/tmp/apm.sock

; HTTP configuration
; Whether to enable the HTTP driver
; apm.http_enabled=On
; Whether to collect stats for the HTTP driver
; apm.http_stats_enabled=On
; Error reporting level specific to the HTTP driver
; apm.http_error_reporting=E_ALL|E_STRICT
; Control which exceptions to collect (0: none exceptions collected, 1: collect uncaught exceptions (default), 2: collect ALL exceptions)
; apm.http_exception_mode=1
; Stores silenced events
; apm.http_process_silenced_events = On
; Server for POSTing events
; apm.http_server=http://localhost
; Client and certificate authority for making the server connection
; apm.http_certificate_authorities=""
; apm.http_client_certificate=""
; apm.http_client_key=""
; Maximum number of characters to include in backtrace (0=unlimited)
; apm.http_max_backtrace_length=0
; Timeout (in ms) for POSTing events
; apm.http_request_timeout=1000

37 changes: 36 additions & 1 deletion config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ PHP_ARG_ENABLE(statsd, enable support for statsd,
[ --enable-statsd Enable statsd support], yes, no)
PHP_ARG_ENABLE(socket, enable support for socket,
[ --enable-socket Enable socket support], yes, no)
PHP_ARG_ENABLE(http, enable support for http,
[ --enable-http Enable HTTP support], yes, no)
PHP_ARG_WITH(debugfile, enable the debug file,
[ --with-debugfile=[FILE] Location of debugging file (/tmp/apm.debug by default)], no, no)
PHP_ARG_WITH(defaultdb, set default sqlite3 default DB path,
Expand Down Expand Up @@ -199,6 +201,39 @@ if test "$PHP_APM" != "no"; then
AC_DEFINE(APM_DRIVER_SOCKET, 1, [activate socket driver])
fi

PHP_NEW_EXTENSION(apm, apm.c backtrace.c $sqlite3_driver $mysql_driver $statsd_driver $socket_driver, $ext_shared)
if test "$PHP_HTTP" != "no"; then
http_driver="driver_http.c"
AC_DEFINE(APM_DRIVER_HTTP, 1, [activate HTTP sending driver])
AC_DEFINE(HAVE_HTTP, 1, [HTTP found and included])

if test -r $PHP_CURL/include/curl/easy.h; then
CURL_DIR=$PHP_CURL
else
AC_MSG_CHECKING(for cURL in default path)
for i in /usr/local /usr; do
if test -r $i/include/curl/easy.h; then
CURL_DIR=$i
AC_MSG_RESULT(found in $i)
break
fi
done
fi

PHP_ADD_INCLUDE($CURL_DIR/include)
PHP_EVAL_LIBLINE($CURL_LIBS, APM_SHARED_LIBADD)
PHP_ADD_LIBRARY_WITH_PATH(curl, $CURL_DIR/$PHP_LIBDIR, APM_SHARED_LIBADD)

PHP_CHECK_LIBRARY(curl,curl_easy_perform,
[
AC_DEFINE(HAVE_CURL,1,[ ])
],[
AC_MSG_ERROR(There is something wrong. Please check config.log for more information.)
],[
$CURL_LIBS -L$CURL_DIR/$PHP_LIBDIR
])

fi

PHP_NEW_EXTENSION(apm, apm.c backtrace.c $sqlite3_driver $mysql_driver $statsd_driver $socket_driver $http_driver, $ext_shared)
PHP_SUBST(APM_SHARED_LIBADD)
fi
143 changes: 143 additions & 0 deletions driver_http.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
+----------------------------------------------------------------------+
| APM stands for Alternative PHP Monitor |
+----------------------------------------------------------------------+
| Copyright (c) 2011-2016 David Strauss |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: David Strauss <[email protected]> |
+----------------------------------------------------------------------+
*/

#include <stdio.h>
#include <curl/curl.h>
#include "php_apm.h"
#include "php_ini.h"

#include "driver_http.h"

ZEND_EXTERN_MODULE_GLOBALS(apm)

APM_DRIVER_CREATE(http)

char *truncate_data(char *input_str, size_t max_len)
{
char *truncated;
input_str = input_str ? input_str : NULL;
if (max_len == 0)
return strdup(input_str);
truncated = strndup(input_str, max_len);
return truncated;
}

/* Insert an event in the backend */
void apm_driver_http_process_event(PROCESS_EVENT_ARGS)
{
CURL *curl;
CURLcode res;

curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
struct curl_slist *headerlist = NULL;
static const char buf[] = "Expect:";
char int2string[64];
char *trace_to_send;
size_t max_len = 0;

if (APM_G(http_max_backtrace_length) >= 0)
max_len = APM_G(http_max_backtrace_length);

trace_to_send = truncate_data(trace, max_len);

sprintf(int2string, "%d", type);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "type",
CURLFORM_COPYCONTENTS, int2string,
CURLFORM_END);

curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_COPYCONTENTS, error_filename ? error_filename : "",
CURLFORM_END);

sprintf(int2string, "%d", error_lineno);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "line",
CURLFORM_COPYCONTENTS, int2string,
CURLFORM_END);

curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "message",
CURLFORM_COPYCONTENTS, msg ? msg : "",
CURLFORM_END);

curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "backtrace",
CURLFORM_COPYCONTENTS, trace_to_send,
CURLFORM_END);

headerlist = curl_slist_append(headerlist, buf);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);

curl_easy_setopt(curl, CURLOPT_URL, APM_G(http_server));
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, APM_G(http_request_timeout));
if (APM_G(http_client_certificate) != NULL) {
curl_easy_setopt(curl, CURLOPT_SSLCERT, APM_G(http_client_certificate));
}
if (APM_G(http_client_key) != NULL) {
curl_easy_setopt(curl, CURLOPT_SSLKEY, APM_G(http_client_key));
}
if (APM_G(http_certificate_authorities) != NULL) {
curl_easy_setopt(curl, CURLOPT_CAINFO, APM_G(http_certificate_authorities));
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
}

res = curl_easy_perform(curl);

APM_DEBUG("[HTTP driver] Result: %s\n", curl_easy_strerror(res));

/* Always clean up. */
curl_easy_cleanup(curl);
free(trace_to_send);
}
}

int apm_driver_http_minit(int module_number)
{
return SUCCESS;
}

int apm_driver_http_rinit()
{
return SUCCESS;
}

int apm_driver_http_mshutdown()
{
return SUCCESS;
}

int apm_driver_http_rshutdown()
{
return SUCCESS;
}

void apm_driver_http_process_stats(TSRMLS_D)
{
}
30 changes: 30 additions & 0 deletions driver_http.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
+----------------------------------------------------------------------+
| APM stands for Alternative PHP Monitor |
+----------------------------------------------------------------------+
| Copyright (c) 2011-2016 David Strauss |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| [email protected] so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: David Strauss <[email protected]> |
+----------------------------------------------------------------------+
*/

#ifndef DRIVER_HTTP_H
#define DRIVER_HTTP_H

#include "zend_API.h"

#define APM_E_http APM_E_ALL

apm_driver_entry * apm_driver_http_create();

PHP_INI_MH(OnUpdateAPMhttpErrorReporting);

#endif
21 changes: 21 additions & 0 deletions php_apm.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,27 @@ ZEND_BEGIN_MODULE_GLOBALS(apm)
apm_event_entry *socket_events;
apm_event_entry **socket_last_event;
#endif

#ifdef APM_DRIVER_HTTP
/* Boolean controlling whether the driver is active or not */
zend_bool http_enabled;
/* Boolean controlling the collection of stats */
zend_bool http_stats_enabled;
/* (unused for HTTP) */
long http_exception_mode;
/* (unused for HTTP) */
int http_error_reporting;
/* Option to process silenced events */
zend_bool http_process_silenced_events;

long http_request_timeout;
char *http_server;
char *http_client_certificate;
char *http_client_key;
char *http_certificate_authorities;
long http_max_backtrace_length;
#endif

ZEND_END_MODULE_GLOBALS(apm)

#ifdef ZTS
Expand Down