From 4b82b7eb01328af99edd02d9f97f835f1bf33b5f Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 10:38:04 +0800 Subject: [PATCH 1/8] reset APC and add a new APCU class --- src/Prometheus/Storage/APC.php | 100 +++-------- src/Prometheus/Storage/APCU.php | 293 ++++++++++++++++++++++++++++++++ 2 files changed, 320 insertions(+), 73 deletions(-) create mode 100644 src/Prometheus/Storage/APCU.php diff --git a/src/Prometheus/Storage/APC.php b/src/Prometheus/Storage/APC.php index b608e49..fb747ce 100644 --- a/src/Prometheus/Storage/APC.php +++ b/src/Prometheus/Storage/APC.php @@ -5,7 +5,6 @@ use Prometheus\MetricFamilySamples; -use RuntimeException; class APC implements Adapter { @@ -26,19 +25,19 @@ public function updateHistogram(array $data) { // Initialize the sum $sumKey = $this->histogramBucketValueKey($data, 'sum'); - $new = apcu_add($sumKey, $this->toInteger(0)); + $new = apc_add($sumKey, $this->toInteger(0)); // If sum does not exist, assume a new histogram and store the metadata if ($new) { - apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + apc_store($this->metaKey($data), json_encode($this->metaData($data))); } // Atomically increment the sum // Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/value.go#L91 $done = false; while (!$done) { - $old = apcu_fetch($sumKey); - $done = apcu_cas($sumKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + $old = apc_fetch($sumKey); + $done = apc_cas($sumKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); } // Figure out in which bucket the observation belongs @@ -51,42 +50,42 @@ public function updateHistogram(array $data) } // Initialize and increment the bucket - apcu_add($this->histogramBucketValueKey($data, $bucketToIncrease), 0); - apcu_inc($this->histogramBucketValueKey($data, $bucketToIncrease)); + apc_add($this->histogramBucketValueKey($data, $bucketToIncrease), 0); + apc_inc($this->histogramBucketValueKey($data, $bucketToIncrease)); } public function updateGauge(array $data) { $valueKey = $this->valueKey($data); if ($data['command'] == Adapter::COMMAND_SET) { - apcu_store($valueKey, $this->toInteger($data['value'])); - apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + apc_store($valueKey, $this->toInteger($data['value'])); + apc_store($this->metaKey($data), json_encode($this->metaData($data))); } else { - $new = apcu_add($valueKey, $this->toInteger(0)); + $new = apc_add($valueKey, $this->toInteger(0)); if ($new) { - apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + apc_store($this->metaKey($data), json_encode($this->metaData($data))); } // Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/value.go#L91 $done = false; while (!$done) { - $old = apcu_fetch($valueKey); - $done = apcu_cas($valueKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + $old = apc_fetch($valueKey); + $done = apc_cas($valueKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); } } } public function updateCounter(array $data) { - $new = apcu_add($this->valueKey($data), 0); + $new = apc_add($this->valueKey($data), 0); if ($new) { - apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + apc_store($this->metaKey($data), json_encode($this->metaData($data))); } - apcu_inc($this->valueKey($data), $data['value']); + apc_inc($this->valueKey($data), $data['value']); } public function flushAPC() { - apcu_clear_cache(); + apc_clear_cache('user'); } /** @@ -104,13 +103,7 @@ private function metaKey(array $data) */ private function valueKey(array $data) { - return implode(':', array( - self::PROMETHEUS_PREFIX, - $data['type'], - $data['name'], - $this->encodeLabelValues($data['labelValues']), - 'value' - )); + return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], json_encode($data['labelValues']), 'value')); } /** @@ -119,14 +112,7 @@ private function valueKey(array $data) */ private function histogramBucketValueKey(array $data, $bucket) { - return implode(':', array( - self::PROMETHEUS_PREFIX, - $data['type'], - $data['name'], - $this->encodeLabelValues($data['labelValues']), - $bucket, - 'value' - )); + return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], json_encode($data['labelValues']), $bucket, 'value')); } /** @@ -148,7 +134,7 @@ private function metaData(array $data) private function collectCounters() { $counters = array(); - foreach (new \APCUIterator('/^prom:counter:.*:meta/') as $counter) { + foreach (new \APCIterator('user', '/^prom:counter:.*:meta/') as $counter) { $metaData = json_decode($counter['value'], true); $data = array( 'name' => $metaData['name'], @@ -156,13 +142,13 @@ private function collectCounters() 'type' => $metaData['type'], 'labelNames' => $metaData['labelNames'], ); - foreach (new \APCUIterator('/^prom:counter:' . $metaData['name'] . ':.*:value/') as $value) { + foreach (new \APCIterator('user', '/^prom:counter:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; $data['samples'][] = array( 'name' => $metaData['name'], 'labelNames' => array(), - 'labelValues' => $this->decodeLabelValues($labelValues), + 'labelValues' => json_decode($labelValues), 'value' => $value['value'] ); } @@ -178,7 +164,7 @@ private function collectCounters() private function collectGauges() { $gauges = array(); - foreach (new \APCUIterator('/^prom:gauge:.*:meta/') as $gauge) { + foreach (new \APCIterator('user', '/^prom:gauge:.*:meta/') as $gauge) { $metaData = json_decode($gauge['value'], true); $data = array( 'name' => $metaData['name'], @@ -186,13 +172,13 @@ private function collectGauges() 'type' => $metaData['type'], 'labelNames' => $metaData['labelNames'], ); - foreach (new \APCUIterator('/^prom:gauge:' . $metaData['name'] . ':.*:value/') as $value) { + foreach (new \APCIterator('user', '/^prom:gauge:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; $data['samples'][] = array( 'name' => $metaData['name'], 'labelNames' => array(), - 'labelValues' => $this->decodeLabelValues($labelValues), + 'labelValues' => json_decode($labelValues), 'value' => $this->fromInteger($value['value']) ); } @@ -209,7 +195,7 @@ private function collectGauges() private function collectHistograms() { $histograms = array(); - foreach (new \APCUIterator('/^prom:histogram:.*:meta/') as $histogram) { + foreach (new \APCIterator('user', '/^prom:histogram:.*:meta/') as $histogram) { $metaData = json_decode($histogram['value'], true); $data = array( 'name' => $metaData['name'], @@ -223,7 +209,7 @@ private function collectHistograms() $data['buckets'][] = '+Inf'; $histogramBuckets = array(); - foreach (new \APCUIterator('/^prom:histogram:' . $metaData['name'] . ':.*:value/') as $value) { + foreach (new \APCIterator('user', '/^prom:histogram:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; $bucket = $parts[4]; @@ -236,7 +222,7 @@ private function collectHistograms() sort($labels); foreach ($labels as $labelValues) { $acc = 0; - $decodedLabelValues = $this->decodeLabelValues($labelValues); + $decodedLabelValues = json_decode($labelValues); foreach ($data['buckets'] as $bucket) { $bucket = (string) $bucket; if (!isset($histogramBuckets[$labelValues][$bucket])) { @@ -303,36 +289,4 @@ private function sortSamples(array &$samples) return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); }); } - - /** - * @param array $values - * @return string - * @throws RuntimeException - */ - private function encodeLabelValues(array $values) - { - $json = json_encode($values); - if (false === $json) { - throw new RuntimeException(json_last_error_msg()); - } - return base64_encode($json); - } - - /** - * @param string $values - * @return array - * @throws RuntimeException - */ - private function decodeLabelValues($values) - { - $json = base64_decode($values, true); - if (false === $json) { - throw new RuntimeException('Cannot base64 decode label values'); - } - $decodedValues = json_decode($json, true); - if (false === $decodedValues) { - throw new RuntimeException(json_last_error_msg()); - } - return $decodedValues; - } } diff --git a/src/Prometheus/Storage/APCU.php b/src/Prometheus/Storage/APCU.php new file mode 100644 index 0000000..98100f7 --- /dev/null +++ b/src/Prometheus/Storage/APCU.php @@ -0,0 +1,293 @@ +collectHistograms(); + $metrics = array_merge($metrics, $this->collectGauges()); + $metrics = array_merge($metrics, $this->collectCounters()); + return $metrics; + } + + public function updateHistogram(array $data) + { + // Initialize the sum + $sumKey = $this->histogramBucketValueKey($data, 'sum'); + $new = apcu_add($sumKey, $this->toInteger(0)); + + // If sum does not exist, assume a new histogram and store the metadata + if ($new) { + apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + } + + // Atomically increment the sum + // Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/value.go#L91 + $done = false; + while (!$done) { + $old = apcu_fetch($sumKey); + $done = apcu_cas($sumKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + } + + // Figure out in which bucket the observation belongs + $bucketToIncrease = '+Inf'; + foreach ($data['buckets'] as $bucket) { + if ($data['value'] <= $bucket) { + $bucketToIncrease = $bucket; + break; + } + } + + // Initialize and increment the bucket + apcu_add($this->histogramBucketValueKey($data, $bucketToIncrease), 0); + apcu_inc($this->histogramBucketValueKey($data, $bucketToIncrease)); + } + + public function updateGauge(array $data) + { + $valueKey = $this->valueKey($data); + if ($data['command'] == Adapter::COMMAND_SET) { + apcu_store($valueKey, $this->toInteger($data['value'])); + apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + } else { + $new = apcu_add($valueKey, $this->toInteger(0)); + if ($new) { + apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + } + // Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/value.go#L91 + $done = false; + while (!$done) { + $old = apcu_fetch($valueKey); + $done = apcu_cas($valueKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); + } + } + } + + public function updateCounter(array $data) + { + $new = apcu_add($this->valueKey($data), 0); + if ($new) { + apcu_store($this->metaKey($data), json_encode($this->metaData($data))); + } + apcu_inc($this->valueKey($data), $data['value']); + } + + public function flushAPC() + { + apcu_clear_cache('user'); + } + + /** + * @param array $data + * @return string + */ + private function metaKey(array $data) + { + return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], 'meta')); + } + + /** + * @param array $data + * @return string + */ + private function valueKey(array $data) + { + return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], json_encode($data['labelValues']), 'value')); + } + + /** + * @param array $data + * @return string + */ + private function histogramBucketValueKey(array $data, $bucket) + { + return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], json_encode($data['labelValues']), $bucket, 'value')); + } + + /** + * @param array $data + * @return array + */ + private function metaData(array $data) + { + $metricsMetaData = $data; + unset($metricsMetaData['value']); + unset($metricsMetaData['command']); + unset($metricsMetaData['labelValues']); + return $metricsMetaData; + } + + /** + * @return array + */ + private function collectCounters() + { + $counters = array(); + foreach (new \APCUIterator('/^prom:counter:.*:meta/') as $counter) { + $metaData = json_decode($counter['value'], true); + $data = array( + 'name' => $metaData['name'], + 'help' => $metaData['help'], + 'type' => $metaData['type'], + 'labelNames' => $metaData['labelNames'], + ); + foreach (new \APCUIterator( '/^prom:counter:' . $metaData['name'] . ':.*:value/') as $value) { + $parts = explode(':', $value['key']); + $labelValues = $parts[3]; + $data['samples'][] = array( + 'name' => $metaData['name'], + 'labelNames' => array(), + 'labelValues' => json_decode($labelValues), + 'value' => $value['value'] + ); + } + $this->sortSamples($data['samples']); + $counters[] = new MetricFamilySamples($data); + } + return $counters; + } + + /** + * @return array + */ + private function collectGauges() + { + $gauges = array(); + foreach (new \APCUIterator('/^prom:gauge:.*:meta/') as $gauge) { + $metaData = json_decode($gauge['value'], true); + $data = array( + 'name' => $metaData['name'], + 'help' => $metaData['help'], + 'type' => $metaData['type'], + 'labelNames' => $metaData['labelNames'], + ); + foreach (new \APCUIterator('/^prom:gauge:' . $metaData['name'] . ':.*:value/') as $value) { + $parts = explode(':', $value['key']); + $labelValues = $parts[3]; + $data['samples'][] = array( + 'name' => $metaData['name'], + 'labelNames' => array(), + 'labelValues' => json_decode($labelValues), + 'value' => $this->fromInteger($value['value']) + ); + } + + $this->sortSamples($data['samples']); + $gauges[] = new MetricFamilySamples($data); + } + return $gauges; + } + + /** + * @return array + */ + private function collectHistograms() + { + $histograms = array(); + + foreach (new \APCUIterator( '/^prom:histogram:.*:meta/') as $histogram) { + $metaData = json_decode($histogram['value'], true); + $data = array( + 'name' => $metaData['name'], + 'help' => $metaData['help'], + 'type' => $metaData['type'], + 'labelNames' => $metaData['labelNames'], + 'buckets' => $metaData['buckets'] + ); + + // Add the Inf bucket so we can compute it later on + $data['buckets'][] = '+Inf'; + + $histogramBuckets = array(); + foreach (new \APCUIterator( '/^prom:histogram:' . $metaData['name'] . ':.*:value/') as $value) { + $parts = explode(':', $value['key']); + $labelValues = $parts[3]; + $bucket = $parts[4]; + // Key by labelValues + $histogramBuckets[$labelValues][$bucket] = $value['value']; + } + + // Compute all buckets + $labels = array_keys($histogramBuckets); + sort($labels); + foreach ($labels as $labelValues) { + $acc = 0; + $decodedLabelValues = json_decode($labelValues); + foreach ($data['buckets'] as $bucket) { + $bucket = (string) $bucket; + if (!isset($histogramBuckets[$labelValues][$bucket])) { + $data['samples'][] = array( + 'name' => $metaData['name'] . '_bucket', + 'labelNames' => array('le'), + 'labelValues' => array_merge($decodedLabelValues, array($bucket)), + 'value' => $acc + ); + } else { + $acc += $histogramBuckets[$labelValues][$bucket]; + $data['samples'][] = array( + 'name' => $metaData['name'] . '_' . 'bucket', + 'labelNames' => array('le'), + 'labelValues' => array_merge($decodedLabelValues, array($bucket)), + 'value' => $acc + ); + } + } + + // Add the count + $data['samples'][] = array( + 'name' => $metaData['name'] . '_count', + 'labelNames' => array(), + 'labelValues' => $decodedLabelValues, + 'value' => $acc + ); + + // Add the sum + $data['samples'][] = array( + 'name' => $metaData['name'] . '_sum', + 'labelNames' => array(), + 'labelValues' => $decodedLabelValues, + 'value' => $this->fromInteger($histogramBuckets[$labelValues]['sum']) + ); + + } + $histograms[] = new MetricFamilySamples($data); + } + return $histograms; + } + + /** + * @param mixed $val + * @return int + */ + private function toInteger($val) + { + return unpack('Q', pack('d', $val))[1]; + } + + /** + * @param mixed $val + * @return int + */ + private function fromInteger($val) + { + return unpack('d', pack('Q', $val))[1]; + } + + private function sortSamples(array &$samples) + { + usort($samples, function($a, $b){ + return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); + }); + } +} From 18ab01a3dc1b159edbbf185bd586695eae542f9c Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 10:43:40 +0800 Subject: [PATCH 2/8] add real APCU tests --- src/Prometheus/Storage/APCU.php | 2 +- .../Prometheus/APCU/CollectorRegistryTest.php | 20 ++++++++++++++++++ tests/Test/Prometheus/APCU/CounterTest.php | 20 ++++++++++++++++++ tests/Test/Prometheus/APCU/GaugeTest.php | 20 ++++++++++++++++++ tests/Test/Prometheus/APCU/HistogramTest.php | 21 +++++++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/Test/Prometheus/APCU/CollectorRegistryTest.php create mode 100644 tests/Test/Prometheus/APCU/CounterTest.php create mode 100644 tests/Test/Prometheus/APCU/GaugeTest.php create mode 100644 tests/Test/Prometheus/APCU/HistogramTest.php diff --git a/src/Prometheus/Storage/APCU.php b/src/Prometheus/Storage/APCU.php index 98100f7..4c4d0ee 100644 --- a/src/Prometheus/Storage/APCU.php +++ b/src/Prometheus/Storage/APCU.php @@ -83,7 +83,7 @@ public function updateCounter(array $data) apcu_inc($this->valueKey($data), $data['value']); } - public function flushAPC() + public function flushAPCU() { apcu_clear_cache('user'); } diff --git a/tests/Test/Prometheus/APCU/CollectorRegistryTest.php b/tests/Test/Prometheus/APCU/CollectorRegistryTest.php new file mode 100644 index 0000000..aa29543 --- /dev/null +++ b/tests/Test/Prometheus/APCU/CollectorRegistryTest.php @@ -0,0 +1,20 @@ +adapter = new APCU(); + $this->adapter->flushAPCU() + } +} diff --git a/tests/Test/Prometheus/APCU/CounterTest.php b/tests/Test/Prometheus/APCU/CounterTest.php new file mode 100644 index 0000000..6bc4ef0 --- /dev/null +++ b/tests/Test/Prometheus/APCU/CounterTest.php @@ -0,0 +1,20 @@ +adapter = new APCU(); + $this->adapter->flushAPCU(); + } +} diff --git a/tests/Test/Prometheus/APCU/GaugeTest.php b/tests/Test/Prometheus/APCU/GaugeTest.php new file mode 100644 index 0000000..9572e9a --- /dev/null +++ b/tests/Test/Prometheus/APCU/GaugeTest.php @@ -0,0 +1,20 @@ +adapter = new APCU(); + $this->adapter->flushAPCU(); + } +} diff --git a/tests/Test/Prometheus/APCU/HistogramTest.php b/tests/Test/Prometheus/APCU/HistogramTest.php new file mode 100644 index 0000000..882de65 --- /dev/null +++ b/tests/Test/Prometheus/APCU/HistogramTest.php @@ -0,0 +1,21 @@ +adapter = new APCU(); + $this->adapter->flushAPCU(); + } +} + From a27bcd1aeffee33b3da68b84f5e644ed21cae6c4 Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 11:13:50 +0800 Subject: [PATCH 3/8] add ; --- tests/Test/Prometheus/APCU/CollectorRegistryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Test/Prometheus/APCU/CollectorRegistryTest.php b/tests/Test/Prometheus/APCU/CollectorRegistryTest.php index aa29543..3e2f631 100644 --- a/tests/Test/Prometheus/APCU/CollectorRegistryTest.php +++ b/tests/Test/Prometheus/APCU/CollectorRegistryTest.php @@ -15,6 +15,6 @@ class CollectorRegistryTest extends AbstractCollectorRegistryTest public function configureAdapter() { $this->adapter = new APCU(); - $this->adapter->flushAPCU() + $this->adapter->flushAPCU(); } } From 56c93e1e07863dadfdeab75902ed0fd59c10b735 Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 11:20:32 +0800 Subject: [PATCH 4/8] fix function apcu_clear_cache --- src/Prometheus/Storage/APCU.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prometheus/Storage/APCU.php b/src/Prometheus/Storage/APCU.php index 4c4d0ee..974837f 100644 --- a/src/Prometheus/Storage/APCU.php +++ b/src/Prometheus/Storage/APCU.php @@ -85,7 +85,7 @@ public function updateCounter(array $data) public function flushAPCU() { - apcu_clear_cache('user'); + apcu_clear_cache(); } /** From 18a65cf7e5eab5e9005c26324c8133647059b67a Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 11:53:00 +0800 Subject: [PATCH 5/8] delete APC test cases --- .../Prometheus/APC/CollectorRegistryTest.php | 20 ------------------ tests/Test/Prometheus/APC/CounterTest.php | 20 ------------------ tests/Test/Prometheus/APC/GaugeTest.php | 20 ------------------ tests/Test/Prometheus/APC/HistogramTest.php | 21 ------------------- 4 files changed, 81 deletions(-) delete mode 100644 tests/Test/Prometheus/APC/CollectorRegistryTest.php delete mode 100644 tests/Test/Prometheus/APC/CounterTest.php delete mode 100644 tests/Test/Prometheus/APC/GaugeTest.php delete mode 100644 tests/Test/Prometheus/APC/HistogramTest.php diff --git a/tests/Test/Prometheus/APC/CollectorRegistryTest.php b/tests/Test/Prometheus/APC/CollectorRegistryTest.php deleted file mode 100644 index 23f7b84..0000000 --- a/tests/Test/Prometheus/APC/CollectorRegistryTest.php +++ /dev/null @@ -1,20 +0,0 @@ -adapter = new APC(); - $this->adapter->flushAPC(); - } -} diff --git a/tests/Test/Prometheus/APC/CounterTest.php b/tests/Test/Prometheus/APC/CounterTest.php deleted file mode 100644 index 5ca3b5d..0000000 --- a/tests/Test/Prometheus/APC/CounterTest.php +++ /dev/null @@ -1,20 +0,0 @@ -adapter = new APC(); - $this->adapter->flushAPC(); - } -} diff --git a/tests/Test/Prometheus/APC/GaugeTest.php b/tests/Test/Prometheus/APC/GaugeTest.php deleted file mode 100644 index f1b2c04..0000000 --- a/tests/Test/Prometheus/APC/GaugeTest.php +++ /dev/null @@ -1,20 +0,0 @@ -adapter = new APC(); - $this->adapter->flushAPC(); - } -} diff --git a/tests/Test/Prometheus/APC/HistogramTest.php b/tests/Test/Prometheus/APC/HistogramTest.php deleted file mode 100644 index 19d41eb..0000000 --- a/tests/Test/Prometheus/APC/HistogramTest.php +++ /dev/null @@ -1,21 +0,0 @@ -adapter = new APC(); - $this->adapter->flushAPC(); - } -} - From 30fe96fd164de35a03cf3386ab2fdaf34c3e728e Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 12:06:11 +0800 Subject: [PATCH 6/8] add json_decode true --- src/Prometheus/Storage/APCU.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Prometheus/Storage/APCU.php b/src/Prometheus/Storage/APCU.php index 974837f..3b3f358 100644 --- a/src/Prometheus/Storage/APCU.php +++ b/src/Prometheus/Storage/APCU.php @@ -148,7 +148,7 @@ private function collectCounters() $data['samples'][] = array( 'name' => $metaData['name'], 'labelNames' => array(), - 'labelValues' => json_decode($labelValues), + 'labelValues' => json_decode($labelValues,true), 'value' => $value['value'] ); } @@ -178,7 +178,7 @@ private function collectGauges() $data['samples'][] = array( 'name' => $metaData['name'], 'labelNames' => array(), - 'labelValues' => json_decode($labelValues), + 'labelValues' => json_decode($labelValues,true), 'value' => $this->fromInteger($value['value']) ); } @@ -223,7 +223,7 @@ private function collectHistograms() sort($labels); foreach ($labels as $labelValues) { $acc = 0; - $decodedLabelValues = json_decode($labelValues); + $decodedLabelValues = json_decode($labelValues,true); foreach ($data['buckets'] as $bucket) { $bucket = (string) $bucket; if (!isset($histogramBuckets[$labelValues][$bucket])) { From 473708e8c41128961a58ccb716b3c489eec02682 Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 12:14:11 +0800 Subject: [PATCH 7/8] fix apcu --- src/Prometheus/Storage/APCU.php | 96 ++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/src/Prometheus/Storage/APCU.php b/src/Prometheus/Storage/APCU.php index 3b3f358..1676fba 100644 --- a/src/Prometheus/Storage/APCU.php +++ b/src/Prometheus/Storage/APCU.php @@ -1,15 +1,10 @@ collectCounters()); return $metrics; } - public function updateHistogram(array $data) { // Initialize the sum $sumKey = $this->histogramBucketValueKey($data, 'sum'); $new = apcu_add($sumKey, $this->toInteger(0)); - // If sum does not exist, assume a new histogram and store the metadata if ($new) { apcu_store($this->metaKey($data), json_encode($this->metaData($data))); } - // Atomically increment the sum // Taken from https://github.com/prometheus/client_golang/blob/66058aac3a83021948e5fb12f1f408ff556b9037/prometheus/value.go#L91 $done = false; @@ -39,7 +31,6 @@ public function updateHistogram(array $data) $old = apcu_fetch($sumKey); $done = apcu_cas($sumKey, $old, $this->toInteger($this->fromInteger($old) + $data['value'])); } - // Figure out in which bucket the observation belongs $bucketToIncrease = '+Inf'; foreach ($data['buckets'] as $bucket) { @@ -48,12 +39,10 @@ public function updateHistogram(array $data) break; } } - // Initialize and increment the bucket apcu_add($this->histogramBucketValueKey($data, $bucketToIncrease), 0); apcu_inc($this->histogramBucketValueKey($data, $bucketToIncrease)); } - public function updateGauge(array $data) { $valueKey = $this->valueKey($data); @@ -73,7 +62,6 @@ public function updateGauge(array $data) } } } - public function updateCounter(array $data) { $new = apcu_add($this->valueKey($data), 0); @@ -82,12 +70,10 @@ public function updateCounter(array $data) } apcu_inc($this->valueKey($data), $data['value']); } - - public function flushAPCU() + public function flushAPC() { apcu_clear_cache(); } - /** * @param array $data * @return string @@ -96,25 +82,35 @@ private function metaKey(array $data) { return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], 'meta')); } - /** * @param array $data * @return string */ private function valueKey(array $data) { - return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], json_encode($data['labelValues']), 'value')); + return implode(':', array( + self::PROMETHEUS_PREFIX, + $data['type'], + $data['name'], + $this->encodeLabelValues($data['labelValues']), + 'value' + )); } - /** * @param array $data * @return string */ private function histogramBucketValueKey(array $data, $bucket) { - return implode(':', array(self::PROMETHEUS_PREFIX, $data['type'], $data['name'], json_encode($data['labelValues']), $bucket, 'value')); + return implode(':', array( + self::PROMETHEUS_PREFIX, + $data['type'], + $data['name'], + $this->encodeLabelValues($data['labelValues']), + $bucket, + 'value' + )); } - /** * @param array $data * @return array @@ -127,7 +123,6 @@ private function metaData(array $data) unset($metricsMetaData['labelValues']); return $metricsMetaData; } - /** * @return array */ @@ -142,13 +137,13 @@ private function collectCounters() 'type' => $metaData['type'], 'labelNames' => $metaData['labelNames'], ); - foreach (new \APCUIterator( '/^prom:counter:' . $metaData['name'] . ':.*:value/') as $value) { + foreach (new \APCUIterator('/^prom:counter:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; $data['samples'][] = array( 'name' => $metaData['name'], 'labelNames' => array(), - 'labelValues' => json_decode($labelValues,true), + 'labelValues' => $this->decodeLabelValues($labelValues), 'value' => $value['value'] ); } @@ -157,7 +152,6 @@ private function collectCounters() } return $counters; } - /** * @return array */ @@ -178,25 +172,22 @@ private function collectGauges() $data['samples'][] = array( 'name' => $metaData['name'], 'labelNames' => array(), - 'labelValues' => json_decode($labelValues,true), + 'labelValues' => $this->decodeLabelValues($labelValues), 'value' => $this->fromInteger($value['value']) ); } - $this->sortSamples($data['samples']); $gauges[] = new MetricFamilySamples($data); } return $gauges; } - /** * @return array */ private function collectHistograms() { $histograms = array(); - - foreach (new \APCUIterator( '/^prom:histogram:.*:meta/') as $histogram) { + foreach (new \APCUIterator('/^prom:histogram:.*:meta/') as $histogram) { $metaData = json_decode($histogram['value'], true); $data = array( 'name' => $metaData['name'], @@ -205,25 +196,22 @@ private function collectHistograms() 'labelNames' => $metaData['labelNames'], 'buckets' => $metaData['buckets'] ); - // Add the Inf bucket so we can compute it later on $data['buckets'][] = '+Inf'; - $histogramBuckets = array(); - foreach (new \APCUIterator( '/^prom:histogram:' . $metaData['name'] . ':.*:value/') as $value) { + foreach (new \APCUIterator('/^prom:histogram:' . $metaData['name'] . ':.*:value/') as $value) { $parts = explode(':', $value['key']); $labelValues = $parts[3]; $bucket = $parts[4]; // Key by labelValues $histogramBuckets[$labelValues][$bucket] = $value['value']; } - // Compute all buckets $labels = array_keys($histogramBuckets); sort($labels); foreach ($labels as $labelValues) { $acc = 0; - $decodedLabelValues = json_decode($labelValues,true); + $decodedLabelValues = $this->decodeLabelValues($labelValues); foreach ($data['buckets'] as $bucket) { $bucket = (string) $bucket; if (!isset($histogramBuckets[$labelValues][$bucket])) { @@ -243,7 +231,6 @@ private function collectHistograms() ); } } - // Add the count $data['samples'][] = array( 'name' => $metaData['name'] . '_count', @@ -251,7 +238,6 @@ private function collectHistograms() 'labelValues' => $decodedLabelValues, 'value' => $acc ); - // Add the sum $data['samples'][] = array( 'name' => $metaData['name'] . '_sum', @@ -259,13 +245,11 @@ private function collectHistograms() 'labelValues' => $decodedLabelValues, 'value' => $this->fromInteger($histogramBuckets[$labelValues]['sum']) ); - } $histograms[] = new MetricFamilySamples($data); } return $histograms; } - /** * @param mixed $val * @return int @@ -274,7 +258,6 @@ private function toInteger($val) { return unpack('Q', pack('d', $val))[1]; } - /** * @param mixed $val * @return int @@ -283,11 +266,40 @@ private function fromInteger($val) { return unpack('d', pack('Q', $val))[1]; } - private function sortSamples(array &$samples) { usort($samples, function($a, $b){ return strcmp(implode("", $a['labelValues']), implode("", $b['labelValues'])); }); } -} + /** + * @param array $values + * @return string + * @throws RuntimeException + */ + private function encodeLabelValues(array $values) + { + $json = json_encode($values); + if (false === $json) { + throw new RuntimeException(json_last_error_msg()); + } + return base64_encode($json); + } + /** + * @param string $values + * @return array + * @throws RuntimeException + */ + private function decodeLabelValues($values) + { + $json = base64_decode($values, true); + if (false === $json) { + throw new RuntimeException('Cannot base64 decode label values'); + } + $decodedValues = json_decode($json, true); + if (false === $decodedValues) { + throw new RuntimeException(json_last_error_msg()); + } + return $decodedValues; + } +} \ No newline at end of file From 4b08ed5daf4d157e84f638cffa72fb5b0ba849d2 Mon Sep 17 00:00:00 2001 From: yuanshuli Date: Thu, 17 Jan 2019 12:28:04 +0800 Subject: [PATCH 8/8] fix apcu --- src/Prometheus/Storage/APCU.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Prometheus/Storage/APCU.php b/src/Prometheus/Storage/APCU.php index 1676fba..db45610 100644 --- a/src/Prometheus/Storage/APCU.php +++ b/src/Prometheus/Storage/APCU.php @@ -70,7 +70,7 @@ public function updateCounter(array $data) } apcu_inc($this->valueKey($data), $data['value']); } - public function flushAPC() + public function flushAPCU() { apcu_clear_cache(); }