Skip to content
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
31 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
3ef7fd5
PHP: Update tests
prateek-kumar-improving Nov 14, 2025
ac30fa4
PHP: Update tests and add exceptions
prateek-kumar-improving Nov 14, 2025
60fbbc6
PHP: Add memory free in 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 valkey_glide_otel_methods.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";
?>
161 changes: 161 additions & 0 deletions examples/otel_public_api_example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<?php

/**
* Comprehensive OpenTelemetry Public API Example for Valkey GLIDE PHP
*
* This example demonstrates the Java-inspired public OTEL APIs:
* - Static initialization and configuration
* - Runtime sample percentage control
* - Manual span creation and management
* - Integration with automatic command tracing
*/

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

echo "=== Valkey GLIDE PHP OpenTelemetry Public API Example ===\n\n";

try {
// 1. Check initial state
echo "1. Initial OpenTelemetry state:\n";
echo " Initialized: " . (ValkeyGlide::isOpenTelemetryInitialized() ? "Yes" : "No") . "\n";
echo " Sample percentage: " . (ValkeyGlide::getOpenTelemetrySamplePercentage() ?? "N/A") . "%\n\n";

// 2. Initialize OpenTelemetry with comprehensive configuration
echo "2. Initializing OpenTelemetry...\n";
$config = [
'traces' => [
'endpoint' => 'file:///tmp/valkey_glide_traces.json',
'sample_percentage' => 100 // Sample all requests for demo
],
'metrics' => [
'endpoint' => 'file:///tmp/valkey_glide_metrics.json'
],
'flush_interval_ms' => 3000 // Flush every 3 seconds
];

$initialized = ValkeyGlide::initOpenTelemetry($config);
echo " Result: " . ($initialized ? "Success" : "Already initialized") . "\n";

// 3. Verify initialization
echo " Post-init state:\n";
echo " Initialized: " . (ValkeyGlide::isOpenTelemetryInitialized() ? "Yes" : "No") . "\n";
echo " Sample percentage: " . ValkeyGlide::getOpenTelemetrySamplePercentage() . "%\n\n";

// 4. Test runtime sample percentage control
echo "3. Testing runtime sample percentage control:\n";
echo " Setting sample percentage to 50%...\n";
ValkeyGlide::setOpenTelemetrySamplePercentage(50);
echo " New sample percentage: " . ValkeyGlide::getOpenTelemetrySamplePercentage() . "%\n\n";

// 5. Create manual spans for custom tracing
echo "4. Creating manual spans for custom operations:\n";

// Create a parent span for the entire user operation
$userOperationSpan = ValkeyGlide::createOpenTelemetrySpan("user-checkout-process");
echo " Created parent span: " . ($userOperationSpan ? "ID $userOperationSpan" : "Failed") . "\n";

// Create child spans for sub-operations
$validationSpan = ValkeyGlide::createOpenTelemetrySpan("validate-user-data");
echo " Created validation span: " . ($validationSpan ? "ID $validationSpan" : "Failed") . "\n";

// Simulate some work
usleep(100000); // 100ms

// End validation span
ValkeyGlide::endOpenTelemetrySpan($validationSpan);
echo " Ended validation span\n";

// 6. Create Valkey client and perform operations (automatic tracing)
echo "\n5. Creating Valkey client and performing operations:\n";

$addresses = [
['host' => 'localhost', 'port' => 6379]
];

try {
$client = new ValkeyGlide(
$addresses,
false, // use_tls
null, // credentials
null, // read_from
null, // request_timeout
null, // reconnect_strategy
null, // client_name
null, // periodic_checks
null, // advanced_config
null, // lazy_connect
0 // database_id
);

echo " Client created successfully\n";

// These operations will be automatically traced
$client->set('otel:demo:key1', 'value1');
echo " SET operation completed\n";

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

// Create another manual span for batch operations
$batchSpan = ValkeyGlide::createOpenTelemetrySpan("batch-operations");

// Perform multiple operations
$client->set('otel:demo:key2', 'value2');
$client->set('otel:demo:key3', 'value3');
$client->mget(['otel:demo:key1', 'otel:demo:key2', 'otel:demo:key3']);

ValkeyGlide::endOpenTelemetrySpan($batchSpan);
echo " Batch operations completed\n";

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

} catch (Exception $e) {
echo " Client operations failed: " . $e->getMessage() . "\n";
echo " (This is expected if Valkey server is not running)\n";
}

// 7. End the parent span
ValkeyGlide::endOpenTelemetrySpan($userOperationSpan);
echo " Ended parent span\n\n";

// 8. Test error conditions
echo "6. Testing error conditions:\n";

try {
ValkeyGlide::setOpenTelemetrySamplePercentage(150); // Invalid percentage
} catch (Exception $e) {
echo " Expected error for invalid percentage: " . $e->getMessage() . "\n";
}

try {
ValkeyGlide::createOpenTelemetrySpan(""); // Empty name
} catch (Exception $e) {
echo " Expected error for empty span name: " . $e->getMessage() . "\n";
}

try {
ValkeyGlide::createOpenTelemetrySpan(str_repeat("a", 300)); // Too long name
} catch (Exception $e) {
echo " Expected error for long span name: " . $e->getMessage() . "\n";
}

// 9. Test duplicate initialization
echo "\n7. Testing duplicate initialization:\n";
$secondInit = ValkeyGlide::initOpenTelemetry($config);
echo " Second initialization result: " . ($secondInit ? "Success" : "Ignored (expected)") . "\n";

// 10. Final state
echo "\n8. Final OpenTelemetry state:\n";
echo " Initialized: " . (ValkeyGlide::isOpenTelemetryInitialized() ? "Yes" : "No") . "\n";
echo " Sample percentage: " . ValkeyGlide::getOpenTelemetrySamplePercentage() . "%\n";

echo "\n=== Example completed successfully! ===\n";
echo "Check the following files for telemetry data:\n";
echo "- /tmp/valkey_glide_traces.json (traces)\n";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Avoid hard-coding /tmp and use an API to get the temp directory.

echo "- /tmp/valkey_glide_metrics.json (metrics)\n";

} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
echo "Stack trace:\n" . $e->getTraceAsString() . "\n";
}
5 changes: 5 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ Requirements:
<file name="valkey_glide_z_common.c" role="src" />
<file name="valkey_glide_z_common.h" role="src" />
<file name="valkey_z_php_methods.c" role="src" />
<file name="valkey_glide_otel.h" role="src" />
<file name="valkey_glide_otel.c" role="src" />
<file name="valkey_glide_otel_methods.c" role="src" />
<file name="valkey_glide_otel_commands.h" role="src" />
<file name="valkey_glide_otel_commands.c" role="src" />
<dir name="src">
<file name="client_constructor_mock.c" role="src" />
<file name="client_constructor_mock.stub.php" role="src" />
Expand Down
73 changes: 73 additions & 0 deletions tests/ValkeyGlideClusterFeaturesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -755,4 +755,77 @@ public function testClusterClientCreateDeleteLoop()
echo "WARNING: Significant memory growth detected: " . round($memoryGrowth / 1024 / 1024, 2) . " MB\n";
}
}

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

try {
// Initialize OpenTelemetry using new public API (Java pattern)
// Note: May already be initialized from previous tests (once per process)
$initResult = ValkeyGlideCluster::initOpenTelemetry($otelConfig);

// Verify initialization (should be true regardless of initResult)
$this->assertTrue(ValkeyGlideCluster::isOpenTelemetryInitialized(), "OpenTelemetry should be initialized");

// Test sample percentage methods
$currentPercentage = ValkeyGlideCluster::getOpenTelemetrySamplePercentage();
$this->assertTrue(is_int($currentPercentage), "Sample percentage should be an integer");
$this->assertTrue($currentPercentage >= 0 && $currentPercentage <= 100, "Sample percentage should be 0-100");

// Test shouldSample method
$shouldSample = ValkeyGlideCluster::shouldSample();
$this->assertTrue(is_bool($shouldSample), "shouldSample should return a boolean");

// Update sample percentage
$updateResult = ValkeyGlideCluster::setOpenTelemetrySamplePercentage(50);
$this->assertTrue($updateResult, "Sample percentage update should succeed");
$newPercentage = ValkeyGlideCluster::getOpenTelemetrySamplePercentage();
$this->assertEquals(50, $newPercentage, "Sample percentage should be updated to 50");

// Test custom span creation (independent of cluster client)
$spanPtr = ValkeyGlideCluster::createOpenTelemetrySpan('test-cluster-operation');
$this->assertNotNull($spanPtr, "Span creation should return a valid pointer");

// End custom span
$endResult = ValkeyGlideCluster::endOpenTelemetrySpan($spanPtr);
$this->assertTrue($endResult, "Span should end successfully");

// Try to create cluster client, but don't fail the OTEL test if cluster setup fails
try {
$client = new ValkeyGlideCluster(
addresses: [['host' => $this->getHost(), 'port' => $this->getPort()]],
use_tls: $this->getTLS(),
credentials: $this->getAuth() ? ['password' => $this->getAuth()] : 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
);

// If cluster client creation succeeds, test basic operations
$client->set('otel:cluster:test', 'value');
$value = $client->get('otel:cluster:test');
$this->assertEquals('value', $value);

$deleteResult = $client->del('otel:cluster:test');
$this->assertEquals(1, $deleteResult);

$client->close();
} catch (Exception $clusterException) {
// Cluster setup may not be available in CI, but OTEL functionality should still work
// Log the cluster error but don't fail the test
error_log("Cluster client creation failed (expected in some CI environments): " . $clusterException->getMessage());
}

} catch (Exception $e) {
$this->fail("OpenTelemetry API failed: " . $e->getMessage());
}
}
}
Loading
Loading