/
zend_scoutapm.h
136 lines (113 loc) · 5.57 KB
/
zend_scoutapm.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* Scout APM extension for PHP
*
* Copyright (C) 2019-
* For license information, please see the LICENSE file.
*/
#ifndef ZEND_SCOUTAPM_H
#define ZEND_SCOUTAPM_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include <zend_extensions.h>
#include <zend_compile.h>
#include <zend_exceptions.h>
#include "ext/standard/php_var.h"
#define PHP_SCOUTAPM_NAME "scoutapm"
#define PHP_SCOUTAPM_VERSION "0.0.4"
/* Extreme amounts of debugging, set to 1 to enable it and `make clean && make` (tests will fail...) */
#define SCOUT_APM_EXT_DEBUGGING 0
PHP_FUNCTION(scoutapm_get_calls);
/* Describes information we store about a recorded stack frame */
typedef struct _scoutapm_stack_frame {
const char *function_name;
double entered;
double exited;
int argc;
zval *argv;
} scoutapm_stack_frame;
typedef struct _scoutapm_disconnected_call_argument_store {
const char *reference;
int argc;
zval *argv;
} scoutapm_disconnected_call_argument_store;
typedef struct _handler_lookup {
const char *function_name;
int index;
} indexed_handler_lookup;
/* These are the "module globals". In non-ZTS mode, they're just regular variables, but means in ZTS mode they get handled properly */
ZEND_BEGIN_MODULE_GLOBALS(scoutapm)
zend_bool handlers_set;
zend_long observed_stack_frames_count;
scoutapm_stack_frame *observed_stack_frames;
zend_long disconnected_call_argument_store_count;
scoutapm_disconnected_call_argument_store *disconnected_call_argument_store;
ZEND_END_MODULE_GLOBALS(scoutapm)
/* Accessor for "module globals" for non-ZTS and ZTS modes. */
#ifdef ZTS
#define SCOUTAPM_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(scoutapm, v)
#else
#define SCOUTAPM_G(v) (scoutapm_globals.v)
#endif
/* zif_handler is not always defined, so define this roughly equivalent */
#if PHP_VERSION_ID < 70200
typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS);
#endif
/* Sometimes this isn't defined, so define it in that case */
#ifndef ZEND_PARSE_PARAMETERS_NONE
#define ZEND_PARSE_PARAMETERS_NONE() if (zend_parse_parameters_none() != SUCCESS) { return; }
#endif
/* The debugging toggle allows us to output unnecessary amounts of information. Because it's a preprocessor flag, this stuff is compiled out */
#if SCOUT_APM_EXT_DEBUGGING == 1
#define SCOUTAPM_DEBUG_MESSAGE(x, ...) php_printf(x, ##__VA_ARGS__)
#else
#define SCOUTAPM_DEBUG_MESSAGE(...) /**/
#endif
/* Shortcut defined to allow using a `char *` with snprintf - determine the size first, allocate, then snprintf */
#define DYNAMIC_MALLOC_SPRINTF(destString, sizeNeeded, fmt, ...) \
sizeNeeded = snprintf(NULL, 0, fmt, ##__VA_ARGS__) + 1; \
destString = (char*)malloc(sizeNeeded); \
snprintf(destString, sizeNeeded, fmt, ##__VA_ARGS__)
/* overload a regular function by wrapping its handler with our own handler */
#define SCOUT_OVERLOAD_FUNCTION(function_name, handler_to_use) \
original_function = zend_hash_str_find_ptr(EG(function_table), function_name, sizeof(function_name) - 1); \
if (original_function != NULL) { \
handler_index = handler_index_for_function(function_name); \
if (handler_index < 0) { \
zend_throw_exception(NULL, "ScoutAPM did not define a handler index for "function_name, 0); \
return FAILURE;\
} \
original_handlers[handler_index] = original_function->internal_function.handler; \
original_function->internal_function.handler = handler_to_use; \
}
/* Don't use this macro directly, use SCOUT_OVERLOAD_STATIC_METHOD or SCOUT_OVERLOAD_METHOD for consistency */
#define SCOUT_OVERLOAD_CLASS_ENTRY_FUNCTION(lowercase_class_name, instance_or_static, method_name, handler_to_use) \
ce = zend_hash_str_find_ptr(CG(class_table), lowercase_class_name, sizeof(lowercase_class_name) - 1); \
if (ce != NULL) { \
original_function = zend_hash_str_find_ptr(&ce->function_table, method_name, sizeof(method_name)-1); \
if (original_function != NULL) { \
handler_index = handler_index_for_function(lowercase_class_name instance_or_static method_name); \
if (handler_index < 0) { \
zend_throw_exception(NULL, "ScoutAPM did not define a handler index for "lowercase_class_name instance_or_static method_name, 0); \
return FAILURE; \
} \
original_handlers[handler_index] = original_function->internal_function.handler; \
original_function->internal_function.handler = handler_to_use; \
} \
}
/* overload a static class method by wrapping its handler with our own handler */
#define SCOUT_OVERLOAD_STATIC_METHOD(lowercase_class_name, method_name, handler_to_use) SCOUT_OVERLOAD_CLASS_ENTRY_FUNCTION(lowercase_class_name, "::", method_name, handler_to_use)
/* overload an instance class method by wrapping its handler with our own handler */
#define SCOUT_OVERLOAD_METHOD(lowercase_class_name, method_name, handler_to_use) SCOUT_OVERLOAD_CLASS_ENTRY_FUNCTION(lowercase_class_name, "->", method_name, handler_to_use)
#define SCOUT_INTERNAL_FUNCTION_PASSTHRU() original_handlers[handler_index_for_function(determine_function_name(execute_data))](INTERNAL_FUNCTION_PARAM_PASSTHRU)
/* these are the string keys used in scoutapm_get_calls associative array return value */
#define SCOUT_GET_CALLS_KEY_FUNCTION "function"
#define SCOUT_GET_CALLS_KEY_ENTERED "entered"
#define SCOUT_GET_CALLS_KEY_EXITED "exited"
#define SCOUT_GET_CALLS_KEY_TIME_TAKEN "time_taken"
#define SCOUT_GET_CALLS_KEY_ARGV "argv"
/* stored argument wrapper constants */
#define SCOUT_WRAPPER_TYPE_CURL "curl_exec"
#define SCOUT_WRAPPER_TYPE_FILE "file"
#endif /* ZEND_SCOUTAPM_H */