Closed goctl closed 7 years ago
@Wshuhao001 What was the problem, in the end?
@andrewhowdencom Ok, I installed apcu success in php7, but failed in php5.5, my php5.5 using the Zend Opcache,I do not know if this is the reason,I made an error when I excute make.
If following apcu, we need to modify the APC.php or add a APCU.php like this:
<?php
namespace Prometheus\Storage;
use Prometheus\MetricFamilySamples;
class APCu implements Adapter
{
const PROMETHEUS_PREFIX = 'prom';
/**
* @return MetricFamilySamples[]
*/
public function collect()
{
$metrics = $this->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();
}
/**
* @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']));
});
}
}
It'd be interesting to see if it happens in PHP 5.6. I think, given PHP 5.5 is EOL, it's unreasonable to expect support for it?
@andrewhowdencom Yeah,the current production environment is using php5.5, we are working to upgrade to php7, but before that, we hope prometheus can support php5.5. I have successfully installed apcu-4.0.10 in php5.5, but when I run the program, there have been pack and unpack problems, through access, I found that APC.php does not support these two functions:
/**
* @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];
}
Official display: 5.6.3 The "q", "Q", "J" and "P" codes were added to enable working with 64-bit numbers. Now I am starting to solve this problem.
I follow the following changes, view the log found no longer error, but no metrics.
/**
* @param mixed $val
* @return int
*/
private function toInteger($val)
{
return unpack('L', pack('f', $val))[1];
}
/**
* @param mixed $val
* @return int
*/
private function fromInteger($val)
{
return unpack('f', pack('L', $val))[1];
}
Well, I succeeded in php5.5. I'm silly, run the flush to cause metrics to emerge, and now everything is fine.
I suppose everything is solved then. But yes, we won't make any efforts to support 5.5.
When I install apcu 5.1.3 extension, add an APCU class to replace the APC class, such as modifying the apc_add to replace apcu_add, but after adding the count by example to get no metrics.