Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ff90f49
PHP: Add OTEL support
prateek-kumar-improving Nov 7, 2025
807b7da
PHP: Update OTEL tests
prateek-kumar-improving Nov 7, 2025
0f76aa7
PHP: Update type errors
prateek-kumar-improving Nov 7, 2025
0a105f6
PHP: Update OTEL tests
prateek-kumar-improving Nov 7, 2025
290db09
PHP: Update OTEL tests
prateek-kumar-improving Nov 7, 2025
f854b3e
PHP: Update OTEL tests
prateek-kumar-improving Nov 7, 2025
dc74a75
PHP: Add OTEL APIs
prateek-kumar-improving Nov 7, 2025
0b5628e
PHP: Update OTEL tests
prateek-kumar-improving Nov 8, 2025
a42f56c
PHP: Remove OTEL stubs
prateek-kumar-improving Nov 12, 2025
4115930
PHP: Add shouldSample API
prateek-kumar-improving Nov 12, 2025
f3fe8ad
PHP: Update formatting in valkey_glide_otel.c
prateek-kumar-improving Nov 12, 2025
27cb998
PHP: Update formatting in valkey_glide_cluster.c
prateek-kumar-improving Nov 12, 2025
a7b757b
PHP: Fix tests/ValkeyGlideFeaturesTest.php
prateek-kumar-improving Nov 12, 2025
94e597e
PHP: Fix tests/ValkeyGlideFeaturesTest.php
prateek-kumar-improving Nov 12, 2025
441398d
PHP: Fix tests/ValkeyGlideClusterFeaturesTest.php
prateek-kumar-improving Nov 12, 2025
4f16dfa
PHP: Fix tests/ValkeyGlideClusterFeaturesTest.php
prateek-kumar-improving Nov 12, 2025
cab3d84
PHP: Update package.xml
prateek-kumar-improving Nov 13, 2025
e7b9418
PHP: Update package.xml
prateek-kumar-improving Nov 13, 2025
e8baa8a
PHP: Update formatting in valkey_glide_otel.c
prateek-kumar-improving Nov 13, 2025
6a3abc8
PHP: Update memory issues
prateek-kumar-improving Nov 13, 2025
b6d87b2
PHP: Update memory issues
prateek-kumar-improving Nov 13, 2025
4848433
PHP: Update valgrind.supp
prateek-kumar-improving Nov 13, 2025
e518a6c
PHP: Update examples
prateek-kumar-improving Nov 14, 2025
1d1593e
PHP: Update examples
prateek-kumar-improving Nov 14, 2025
b7c13b8
PHP: Update examples and stubs
prateek-kumar-improving Nov 14, 2025
716f3b0
PHP: Update examples and remove public APIs from stubs
prateek-kumar-improving Nov 14, 2025
3e30be6
PHP: Update valkey_glide_otel_should_sample
prateek-kumar-improving Nov 14, 2025
c589fac
PHP: Update valkey_glide_otel.c
prateek-kumar-improving Nov 14, 2025
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
2 changes: 1 addition & 1 deletion config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ if test "$PHP_VALKEY_GLIDE" != "no"; then
esac

PHP_NEW_EXTENSION(valkey_glide,
valkey_glide.c valkey_glide_cluster.c cluster_scan_cursor.c command_response.c logger.c valkey_glide_commands.c valkey_glide_commands_2.c valkey_glide_commands_3.c valkey_glide_core_commands.c valkey_glide_core_common.c valkey_glide_expire_commands.c valkey_glide_geo_commands.c valkey_glide_geo_common.c valkey_glide_hash_common.c valkey_glide_list_common.c valkey_glide_s_common.c valkey_glide_str_commands.c valkey_glide_x_commands.c valkey_glide_x_common.c valkey_glide_z.c valkey_glide_z_common.c valkey_z_php_methods.c src/command_request.pb-c.c src/connection_request.pb-c.c src/response.pb-c.c src/client_constructor_mock.c,
valkey_glide.c valkey_glide_cluster.c cluster_scan_cursor.c command_response.c logger.c valkey_glide_commands.c valkey_glide_commands_2.c valkey_glide_commands_3.c valkey_glide_core_commands.c valkey_glide_core_common.c valkey_glide_expire_commands.c valkey_glide_geo_commands.c valkey_glide_geo_common.c valkey_glide_hash_common.c valkey_glide_list_common.c valkey_glide_s_common.c valkey_glide_str_commands.c valkey_glide_x_commands.c valkey_glide_x_common.c valkey_glide_z.c valkey_glide_z_common.c valkey_z_php_methods.c valkey_glide_otel.c valkey_glide_otel_commands.c src/command_request.pb-c.c src/connection_request.pb-c.c src/response.pb-c.c src/client_constructor_mock.c,
$ext_shared,, $VALKEY_GLIDE_SHARED_LIBADD)

dnl Add FFI library only for macOS (keep Mac working as before)
Expand Down
78 changes: 78 additions & 0 deletions examples/otel_example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
/**
* Example demonstrating OpenTelemetry integration with Valkey GLIDE PHP
* Following Java/Go patterns with proper defaults
*/

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

try {
// OTEL configuration for traces and metrics
// Following Java/Go defaults: sample_percentage=1%, flush_interval_ms=5000
$otelConfig = [
'traces' => [
'endpoint' => 'grpc://localhost:4317', // OTEL collector endpoint
'sample_percentage' => 10 // Sample 10% of requests (default is 1%)
],
'metrics' => [
'endpoint' => 'grpc://localhost:4317' // OTEL collector endpoint
],
'flush_interval_ms' => 5000 // Flush every 5 seconds (default)
];

// Create ValkeyGlide client with OTEL configuration
$client = new ValkeyGlide(
addresses: [
['host' => 'localhost', 'port' => 6379]
],
use_tls: false,
credentials: null,
read_from: ValkeyGlide::READ_FROM_PRIMARY,
request_timeout: null,
reconnect_strategy: null,
database_id: 0,
client_name: 'otel-example-client',
client_az: null,
advanced_config: [
'connection_timeout' => 5000,
'otel' => $otelConfig // Add OTEL configuration
]
);

echo "ValkeyGlide client created with OpenTelemetry support\n";
echo "- Sample percentage: 10% (higher than default 1% for demo)\n";
echo "- Flush interval: 5000ms (default)\n";
echo "- Traces endpoint: grpc://localhost:4317\n";
echo "- Metrics endpoint: grpc://localhost:4317\n\n";

// Perform some operations that will be traced
$client->set('otel:test:key1', 'value1');
echo "SET operation completed\n";

$value = $client->get('otel:test:key1');
echo "GET operation completed: $value\n";

$client->set('otel:test:key2', 'value2');
$client->set('otel:test:key3', 'value3');

// Batch operations will also be traced
$results = $client->mget(['otel:test:key1', 'otel:test:key2', 'otel:test:key3']);
echo "MGET operation completed: " . json_encode($results) . "\n";

// Cleanup
$client->del(['otel:test:key1', 'otel:test:key2', 'otel:test:key3']);
echo "Cleanup completed\n";

$client->close();
echo "Client closed\n";

} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
exit(1);
}

echo "\nOpenTelemetry example completed successfully!\n";
echo "Check your OTEL collector for traces and metrics.\n";
echo "\nNote: OTEL can only be initialized once per process (like Java/Go).\n";
echo "If you need to change configuration, restart the process.\n";
?>
191 changes: 191 additions & 0 deletions tests/ValkeyGlideOtelTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
<?php

require_once 'TestSuite.php';

class ValkeyGlideOtelTest extends TestSuite
{
public function testOtelConfigurationParsing()
{
// Test that OTEL configuration is accepted without errors
$otelConfig = [
'traces' => [
Copy link
Collaborator

Choose a reason for hiding this comment

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

I know we've been primarily taking in associative arrays, but this structure looks really complicated and error prone. It has multiple levels of nesting and a user can have a typo or use the wrong type for any of them. @asafpamzn what do you think of using a class to represent this instead of a complicated array?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@jduo , I agree, new APIs should be with classes

'endpoint' => 'grpc://localhost:4317',
'sample_percentage' => 50
],
'metrics' => [
'endpoint' => 'grpc://localhost:4317'
],
'flush_interval_ms' => 2000
];

try {
$client = new ValkeyGlide(
addresses: [['host' => 'localhost', 'port' => 6379]],
use_tls: false,
credentials: null,
read_from: ValkeyGlide::READ_FROM_PRIMARY,
request_timeout: null,
reconnect_strategy: null,
database_id: 0,
client_name: 'otel-test-client',
client_az: null,
advanced_config: [
'connection_timeout' => 5000,
'otel' => $otelConfig
]
);

// If we get here, OTEL config was accepted
$this->assertTrue(true);
$client->close();
} catch (Exception $e) {
// OTEL config should not cause construction to fail
$this->fail("OTEL configuration caused client construction to fail: " . $e->getMessage());
}
}

public function testOtelWithTracesOnly()
{
$otelConfig = [
'traces' => [
'endpoint' => 'file:///tmp/valkey-traces.json',
'sample_percentage' => 100
]
];

try {
$client = new ValkeyGlide(
addresses: [['host' => 'localhost', 'port' => 6379]],
use_tls: false,
credentials: null,
read_from: ValkeyGlide::READ_FROM_PRIMARY,
request_timeout: null,
reconnect_strategy: null,
database_id: 0,
client_name: 'otel-traces-test',
client_az: null,
advanced_config: [
'otel' => $otelConfig
]
);

// Perform some operations to generate traces
$client->set('otel:trace:test', 'value');
$value = $client->get('otel:trace:test');
$this->assertEquals('value', $value);
$client->del('otel:trace:test');

$client->close();
$this->assertTrue(true);
} catch (Exception $e) {
$this->fail("Traces-only OTEL config failed: " . $e->getMessage());
}
}

public function testOtelWithMetricsOnly()
{
$otelConfig = [
'metrics' => [
'endpoint' => 'file:///tmp/valkey-metrics.json'
]
];

try {
$client = new ValkeyGlide(
addresses: [['host' => 'localhost', 'port' => 6379]],
use_tls: false,
credentials: null,
read_from: ValkeyGlide::READ_FROM_PRIMARY,
request_timeout: null,
reconnect_strategy: null,
database_id: 0,
client_name: 'otel-metrics-test',
client_az: null,
advanced_config: [
'otel' => $otelConfig
]
);

// Perform some operations to generate metrics
$client->set('otel:metric:test', 'value');
$client->get('otel:metric:test');
$client->del('otel:metric:test');

$client->close();
$this->assertTrue(true);
} catch (Exception $e) {
$this->fail("Metrics-only OTEL config failed: " . $e->getMessage());
}
}

public function testOtelClusterSupport()
{
$otelConfig = [
'traces' => [
'endpoint' => 'file:///tmp/valkey-cluster-traces.json',
'sample_percentage' => 100
]
];

try {
$client = new ValkeyGlideCluster(
addresses: [['host' => 'localhost', 'port' => 7001]],
use_tls: false,
credentials: null,
read_from: ValkeyGlide::READ_FROM_PRIMARY,
request_timeout: null,
reconnect_strategy: null,
client_name: 'otel-cluster-test',
periodic_checks: ValkeyGlideCluster::PERIODIC_CHECK_ENABLED_DEFAULT_CONFIGS,
client_az: null,
advanced_config: [
'otel' => $otelConfig
]
);

// Perform cluster operations to generate traces
$client->set('otel:cluster:test', 'value');
$value = $client->get('otel:cluster:test');
$this->assertEquals('value', $value);
$client->del('otel:cluster:test');

$client->close();
$this->assertTrue(true);
} catch (Exception $e) {
$this->fail("Cluster OTEL config failed: " . $e->getMessage());
}
}

public function testOtelWithoutConfiguration()
{
// Test that client works normally without OTEL config
try {
$client = new ValkeyGlide(
addresses: [['host' => 'localhost', 'port' => 6379]],
use_tls: false,
credentials: null,
read_from: ValkeyGlide::READ_FROM_PRIMARY,
request_timeout: null,
reconnect_strategy: null,
database_id: 0,
client_name: 'no-otel-test',
client_az: null,
advanced_config: [
'connection_timeout' => 5000
// No OTEL config
]
);

// Operations should work normally
$client->set('no:otel:test', 'value');
$value = $client->get('no:otel:test');
$this->assertEquals('value', $value);
$client->del('no:otel:test');

$client->close();
$this->assertTrue(true);
} catch (Exception $e) {
$this->fail("Client without OTEL should work normally: " . $e->getMessage());
}
}
}
11 changes: 11 additions & 0 deletions valkey_glide.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "valkey_glide_cluster_arginfo.h" // Include generated arginfo header
#include "valkey_glide_commands_common.h"
#include "valkey_glide_hash_common.h"
#include "valkey_glide_otel.h" // Include OTEL support

/* Enum support includes - must be BEFORE arginfo includes */
#if PHP_VERSION_ID >= 80100
Expand Down Expand Up @@ -389,6 +390,16 @@ void valkey_glide_build_client_config_base(valkey_glide_php_common_constructor_p
} else {
config->advanced_config->tls_config = NULL;
}

/* Check for OTEL config */
zval* otel_config_val = zend_hash_str_find(advanced_ht, "otel", sizeof("otel") - 1);
if (otel_config_val && Z_TYPE_P(otel_config_val) == IS_ARRAY) {
VALKEY_LOG_DEBUG("otel_config", "Processing OTEL configuration from advanced_config");
if (!valkey_glide_otel_init(otel_config_val)) {
VALKEY_LOG_WARN("otel_config",
"Failed to initialize OTEL, continuing without tracing");
}
}
} else {
config->advanced_config = NULL;
}
Expand Down
5 changes: 4 additions & 1 deletion valkey_glide.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,10 @@ class ValkeyGlide
* @param string|null $client_name Client name identifier.
* @param string|null $client_az Client availability zone.
* @param array|null $advanced_config Advanced configuration ['connection_timeout' => 5000,
* 'tls_config' => ['use_insecure_tls' => false]].
* 'tls_config' => ['use_insecure_tls' => false],
* 'otel' => ['traces' => ['endpoint' => 'grpc://localhost:4317', 'sample_percentage' => 1],
* 'metrics' => ['endpoint' => 'grpc://localhost:4317'],
* 'flush_interval_ms' => 5000]].
* connection_timeout is in milliseconds.
* @param bool|null $lazy_connect Whether to use lazy connection.
*/
Expand Down
3 changes: 3 additions & 0 deletions valkey_glide_cluster.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ class ValkeyGlideCluster
* - 'tls_config' => ['use_insecure_tls' => false]
* - 'refresh_topology_from_initial_nodes' => false (default: false)
* When true, topology updates use only initial nodes instead of internal cluster view.
* - 'otel' => ['traces' => ['endpoint' => 'grpc://localhost:4317', 'sample_percentage' => 1],
* 'metrics' => ['endpoint' => 'grpc://localhost:4317'],
* 'flush_interval_ms' => 5000]
* @param bool|null $lazy_connect Whether to use lazy connection.
* @param int|null $database_id Index of the logical database to connect to. Must be non-negative
* and within the range supported by the server configuration.
Expand Down
Loading
Loading