Skip to content

Codex/implement php apm with c for linux gek86k#5

Open
omerfdmrl wants to merge 2 commits into
mainfrom
codex/implement-php-apm-with-c-for-linux-gek86k
Open

Codex/implement php apm with c for linux gek86k#5
omerfdmrl wants to merge 2 commits into
mainfrom
codex/implement-php-apm-with-c-for-linux-gek86k

Conversation

@omerfdmrl

Copy link
Copy Markdown
Owner

No description provided.

Comment thread .aignore
@@ -0,0 +1 @@
config.m4

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[INFO] Adding a .aignore entry for config.m4 will prevent this file from being processed by tools that respect .aignore. Ensure that config.m4 does not contain any required configuration for the build or deployment, as it will now be ignored.

Comment thread README.md
- **Native C extension** for low-level telemetry (CPU, wall time, memory, sampling, errors/exceptions).
- **PHP userland layer** that converts native telemetry to OpenTelemetry traces and metrics.

The extension targets **PHP 8.1+** on Linux and uses **CLOCK_THREAD_CPUTIME_ID** for CPU and **CLOCK_MONOTONIC** for wall time.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider clarifying platform support: the extension currently targets Linux; note whether Windows/macOS are supported or if there are plans for cross‑platform builds.

Comment thread README.md
```ini
extension=apm
apm.enabled=1
apm.enable_sampling=1

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The apm.sample_interval_us setting is in microseconds; consider adding a note about the unit and typical values to help users configure it correctly.

Comment thread config.m4
@@ -0,0 +1,7 @@
PHP_ARG_ENABLE(apm, whether to enable apm support,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[ERROR] The repository's .aignore now lists config.m4, which means this file will be ignored by tools that respect .aignore. As a result, the PHP extension may not be configured or built correctly. Consider removing config.m4 from .aignore or adjusting the ignore rules.

Comment thread examples/otel_bridge.php
use OpenTelemetry\SDK\Trace\SpanExporter\OtlpHttpExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;

require __DIR__ . '/vendor/autoload.php';

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The script assumes a vendor/autoload.php exists relative to this file. In many setups the example may be run from a different working directory, causing a fatal error. Consider using an absolute path or checking file existence before requiring.

Comment thread examples/otel_bridge.php
require __DIR__ . '/vendor/autoload.php';

$resource = ResourceInfo::create(['service.name' => 'php-apm-service']);
$exporter = new OtlpHttpExporter('http://localhost:4318/v1/traces');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The OtlpHttpExporter URL is hard‑coded to localhost:4318. In production this will likely need to be configurable via environment variable or config file.

Comment thread php_apm.h
#define PHP_APM_H

#include <stdint.h>
#include <stdio.h>

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The <stdio.h> header is included but not used anywhere in this file. Consider removing it to reduce compilation overhead and avoid unnecessary dependencies.

Comment thread .aignore
@@ -0,0 +1 @@
config.m4

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[INFO] Adding .aignore to block config.m4 is fine. Ensure that this pattern does not unintentionally prevent needed configuration files from being accessed in the future.

@omerfdmrl

Copy link
Copy Markdown
Owner Author

[INFO] The addition of .aignore to exclude config.m4 seems appropriate. Verify that the build or deployment processes respect .aignore and that no required files are inadvertently ignored.

@omerfdmrl

Copy link
Copy Markdown
Owner Author

[INFO] The new README provides a clear overview of the hybrid PHP APM agent, build instructions, and configuration details. Consider adding a brief licensing notice and a link to contribution guidelines for completeness, but otherwise the documentation looks solid.

Comment thread README.md

- Sampling is enabled by default; function-level timing is gated to avoid overhead.
- Stack samples are captured in a ring buffer and flushed in userland.
- Flamegraphs can be generated from sampled stacks (folded stack format).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider adding a License section (e.g., MIT) at the end of the README to clarify usage rights.

Comment thread config.m4
@@ -0,0 +1,7 @@
PHP_ARG_ENABLE(apm, whether to enable apm support,
[ --enable-apm Enable apm support])

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[INFO] The description for the --enable-apm flag is concise, but consider adding a brief note about the default behavior (disabled) for clarity to users.

Comment thread config.m4
@@ -0,0 +1,7 @@
PHP_ARG_ENABLE(apm, whether to enable apm support,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[INFO] Consider specifying the default value (e.g., "no") in PHP_ARG_ENABLE to make the default behavior explicit for users.

Comment thread examples/otel_bridge.php
require __DIR__ . '/vendor/autoload.php';

$resource = ResourceInfo::create(['service.name' => 'php-apm-service']);
$exporter = new OtlpHttpExporter('http://localhost:4318/v1/traces');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The OTLP endpoint URL is hard‑coded. Consider making it configurable via an environment variable or configuration file to allow different deployment environments.

Comment thread examples/otel_bridge.php

require __DIR__ . '/vendor/autoload.php';

$resource = ResourceInfo::create(['service.name' => 'php-apm-service']);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The service name is hard‑coded. Consider making it configurable (e.g., via env var) so the same code can be reused across services.

Comment thread examples/otel_bridge.php
$span->recordException($e);
$span->setStatus(StatusCode::STATUS_ERROR, $e->getMessage());
} finally {
$metrics = apm_get_request_metrics();

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] Ensure the APM extension is loaded before calling apm_get_request_metrics() etc., otherwise this will cause a fatal error if the extension is missing.

@omerfdmrl

Copy link
Copy Markdown
Owner Author

[INFO] Added .aignore to exclude config.m4 from repository scans. This helps keep sensitive configuration files out of version control and complies with the project's ignore policies.

Comment thread README.md
- **Native C extension** for low-level telemetry (CPU, wall time, memory, sampling, errors/exceptions).
- **PHP userland layer** that converts native telemetry to OpenTelemetry traces and metrics.

The extension targets **PHP 8.1+** on Linux and uses **CLOCK_THREAD_CPUTIME_ID** for CPU and **CLOCK_MONOTONIC** for wall time.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The extension currently targets Linux only. It would be helpful to note any platform limitations or future plans for macOS/Windows support.

Comment thread README.md

```sh
phpize
./configure --enable-apm

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider adding a comment that the value is in microseconds to avoid confusion for users adjusting the sampling interval.

Comment thread README.md
extension=apm
apm.enabled=1
apm.enable_sampling=1
apm.sample_interval_us=10000

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider adding a comment that the value is in microseconds to avoid confusion for users adjusting the sampling interval.

Comment thread examples/otel_bridge.php
use OpenTelemetry\SDK\Trace\SpanExporter\OtlpHttpExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;

require __DIR__ . '/vendor/autoload.php';

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider checking that the autoload file exists before requiring it to avoid a fatal error when the example is run outside of a Composer-installed environment.

Comment thread examples/otel_bridge.php
require __DIR__ . '/vendor/autoload.php';

$resource = ResourceInfo::create(['service.name' => 'php-apm-service']);
$exporter = new OtlpHttpExporter('http://localhost:4318/v1/traces');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The OTLP endpoint URL is hard‑coded. Consider making it configurable via an environment variable or configuration file to allow different deployment environments.

Comment thread php_apm.c

static uint32_t apm_ring_next(uint32_t value, uint32_t capacity)
{
value++;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] The apm_ring_next function assumes capacity is non-zero. If APM_G(buffer_size) were set to 0, this could cause a division by zero or infinite loop. Consider adding a guard to handle zero capacity gracefully.

Comment thread php_apm.c
return apm_clock_now(CLOCK_THREAD_CPUTIME_ID);
}

static void apm_log(const char *format, ...)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] apm_log logs every call as E_NOTICE which may flood logs in production. Consider using a lower log level or making logging configurable.

Comment thread php_apm.c
apm_ring_push_sample(&entry, &cpu_point);
}

static void apm_sampler_signal_handler(int signo)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[CRITICAL] The signal handler apm_sampler_signal_handler invokes apm_capture_sample, which uses many PHP runtime functions (e.g., zend hash operations, memory allocation). These are not async-signal-safe and can cause undefined behavior or crashes. Consider redesigning sampling to use a safe flag set in the handler and perform the capture in the main request loop.

Comment thread README.md
@@ -0,0 +1,59 @@
# PHP APM (Hybrid C + PHP OpenTelemetry)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider adding a brief "License" section to clarify the project's licensing terms for downstream users.

Comment thread README.md
## Build and install

```sh
phpize

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider adding a note about required build dependencies (e.g., php-dev, autoconf, libtool) before running phpize and configure, to help users set up the environment correctly.

Comment thread examples/otel_bridge.php
require __DIR__ . '/vendor/autoload.php';

$resource = ResourceInfo::create(['service.name' => 'php-apm-service']);
$exporter = new OtlpHttpExporter('http://localhost:4318/v1/traces');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider reading the OTLP endpoint from an environment variable (e.g., OTEL_EXPORTER_OTLP_ENDPOINT) instead of hard‑coding http://localhost:4318/v1/traces. This makes the example more flexible for different deployment environments.

Comment thread examples/otel_bridge.php
use OpenTelemetry\SDK\Trace\SpanExporter\OtlpHttpExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;

require __DIR__ . '/vendor/autoload.php';

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The autoload path assumes a vendor directory next to this script. Consider using Composer's autoload via require __DIR__.'/../vendor/autoload.php'; or checking for its existence to avoid runtime errors when the example is run from a different location.

Comment thread php_apm.c
{
apm_globals->enabled = 1;
apm_globals->enable_sampling = 1;
apm_globals->enable_function_timing = 0;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] Consider validating that apm.sample_interval_us is greater than zero. A zero interval would create a timer with no delay, potentially causing a busy loop and high CPU usage.

@omerfdmrl

Copy link
Copy Markdown
Owner Author

[INFO] The PR adds a new .aignore file that blocks config.m4. Ensure that this file is not required for the build or runtime, as it will now be ignored by tooling that respects .aignore.

Comment thread README.md

This repository provides a production-grade **hybrid** PHP APM agent:

- **Native C extension** for low-level telemetry (CPU, wall time, memory, sampling, errors/exceptions).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] Consider adding a brief explanation of what "hybrid" means in this context (i.e., combination of native C extension and PHP userland) for readers unfamiliar with the term.

Comment thread examples/otel_bridge.php
use OpenTelemetry\SDK\Trace\SpanExporter\OtlpHttpExporter;
use OpenTelemetry\SDK\Trace\SpanProcessor\SimpleSpanProcessor;

require __DIR__ . '/vendor/autoload.php';

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[SUGGESTION] The script assumes a vendor/autoload.php exists relative to this file. Ensure the example includes installation instructions or uses a more robust autoload path to avoid runtime errors.

Comment thread php_apm.c

ZEND_DECLARE_MODULE_GLOBALS(apm)

static uint64_t apm_clock_now(clockid_t clock_id)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] The apm_clock_now function returns 0 on clock_gettime failure, which is indistinguishable from a valid timestamp of 0. Consider returning an error indicator or logging the failure to avoid silent incorrect timing data.

Comment thread php_apm.c
}
}

static void apm_ring_init(uint32_t capacity)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] apm_ring_init should validate that capacity is greater than zero before allocating memory. A zero capacity would allocate zero‑length buffers and later cause dereferencing NULL pointers in apm_ring_push_sample. Consider adding a guard and fallback to a safe default size.

Comment thread php_apm.c
apm_globals->enabled = 1;
apm_globals->enable_sampling = 1;
apm_globals->enable_function_timing = 0;
apm_globals->sample_interval_us = 10000;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] The INI setting apm.buffer_size is assigned directly without validation. If a user configures a zero or excessively large value, memory allocation in apm_ring_init may fail or allocate zero‑length buffers, leading to crashes. Consider adding a sanity check (e.g., enforce a minimum of 1 and a reasonable maximum).

Comment thread php_apm.c
APM_G(ring).head = 0;
APM_G(ring).tail = 0;
APM_G(ring).dropped = 0;
APM_G(ring).samples = ecalloc(capacity, sizeof(apm_sample_entry));

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] Memory allocation with ecalloc for samples and cpu_points is not checked for failure. If allocation returns NULL, subsequent dereferences will segfault. Consider checking the return value and handling OOM gracefully.

Comment thread php_apm.h
zend_bool enabled;
zend_bool enable_sampling;
zend_bool enable_function_timing;
zend_long sample_interval_us;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[WARNING] sample_interval_us is defined as zend_long (signed). Since it represents a duration in microseconds, a negative value would be nonsensical and could cause timer calculations to behave incorrectly. Consider using an unsigned type (e.g., zend_ulong or uint64_t) and validate the value in the INI handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant