mirror of
https://github.com/danog/MadelineProto.git
synced 2025-01-23 04:11:11 +01:00
Add support for pyroscope memory profiling
This commit is contained in:
parent
a2c759cd0b
commit
20f308c49d
@ -31,7 +31,7 @@ use danog\MadelineProto\EventHandler\Filter\Combinator\FiltersAnd;
|
||||
use danog\MadelineProto\EventHandler\Filter\Filter;
|
||||
use danog\MadelineProto\EventHandler\Filter\FilterAllowAll;
|
||||
use danog\MadelineProto\EventHandler\Update;
|
||||
use danog\MadelineProto\Settings\Prometheus;
|
||||
use danog\MadelineProto\Settings\Metrics;
|
||||
use Generator;
|
||||
use PhpParser\Node\Name;
|
||||
use ReflectionAttribute;
|
||||
@ -130,16 +130,19 @@ abstract class EventHandler extends AbstractAPI
|
||||
self::cachePlugins(static::class);
|
||||
$settings ??= new SettingsEmpty;
|
||||
$API = new API($session, $settings);
|
||||
$prometheus = false;
|
||||
if ($settings instanceof Settings) {
|
||||
$settings = $settings->getPrometheus();
|
||||
$settings = $settings->getMetrics();
|
||||
}
|
||||
if ($settings instanceof Prometheus) {
|
||||
$prometheus = $settings->getReturnMetricsFromStartAndLoop();
|
||||
}
|
||||
if (isset($_GET['metrics']) && $prometheus) {
|
||||
if ($settings instanceof Metrics
|
||||
&& $settings->getReturnMetricsFromStartAndLoop()
|
||||
) {
|
||||
if (isset($_GET['metrics'])) {
|
||||
Tools::closeConnection($API->renderPromStats());
|
||||
return;
|
||||
} elseif (isset($_GET['pprof'])) {
|
||||
Tools::closeConnection($API->getMemoryProfile());
|
||||
return;
|
||||
}
|
||||
}
|
||||
$API->startAndLoopInternal(static::class);
|
||||
}
|
||||
|
@ -939,6 +939,13 @@ abstract class InternalDoc
|
||||
{
|
||||
return \danog\MadelineProto\Tools::getMaxMaps();
|
||||
}
|
||||
/**
|
||||
* Get memory profile with memprof.
|
||||
*/
|
||||
final public function getMemoryProfile(): string
|
||||
{
|
||||
return $this->wrapper->getAPI()->getMemoryProfile();
|
||||
}
|
||||
/**
|
||||
* Get TL namespaces.
|
||||
*/
|
||||
|
@ -20,6 +20,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace danog\MadelineProto;
|
||||
|
||||
use Amp\ByteStream\ReadableBuffer;
|
||||
use Amp\Cache\Cache;
|
||||
use Amp\Cache\LocalCache;
|
||||
use Amp\Cancellation;
|
||||
@ -65,6 +66,7 @@ use danog\MadelineProto\MTProtoTools\PasswordCalculator;
|
||||
use danog\MadelineProto\MTProtoTools\PeerDatabase;
|
||||
use danog\MadelineProto\MTProtoTools\PeerHandler;
|
||||
use danog\MadelineProto\MTProtoTools\ReferenceDatabase;
|
||||
use danog\MadelineProto\MTProtoTools\ResponseInfo;
|
||||
use danog\MadelineProto\MTProtoTools\UpdateHandler;
|
||||
use danog\MadelineProto\Settings\Database\DriverDatabaseAbstract;
|
||||
use danog\MadelineProto\Settings\TLSchema;
|
||||
@ -543,7 +545,7 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
*/
|
||||
public function getPromGauge(string $namespace, string $name, string $help, array $labels = []): ?BetterGauge
|
||||
{
|
||||
if (!$this->getSettings()->getPrometheus()->getEnableCollection()) {
|
||||
if (!$this->getSettings()->getMetrics()->getEnablePrometheusCollection()) {
|
||||
return null;
|
||||
}
|
||||
return GarbageCollector::$prometheus->getOrRegisterGauge(
|
||||
@ -563,7 +565,7 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
*/
|
||||
public function getPromCounter(string $namespace, string $name, string $help, array $labels = []): ?BetterCounter
|
||||
{
|
||||
if (!$this->getSettings()->getPrometheus()->getEnableCollection()) {
|
||||
if (!$this->getSettings()->getMetrics()->getEnablePrometheusCollection()) {
|
||||
return null;
|
||||
}
|
||||
return GarbageCollector::$prometheus->getOrRegisterCounter(
|
||||
@ -584,7 +586,7 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
*/
|
||||
public function getPromSummary(string $namespace, string $name, string $help, array $labels = [], int $maxAgeSeconds = 600, ?array $quantiles = null): ?BetterSummary
|
||||
{
|
||||
if (!$this->getSettings()->getPrometheus()->getEnableCollection()) {
|
||||
if (!$this->getSettings()->getMetrics()->getEnablePrometheusCollection()) {
|
||||
return null;
|
||||
}
|
||||
return GarbageCollector::$prometheus->getOrRegisterSummary(
|
||||
@ -607,7 +609,7 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
*/
|
||||
public function getPromHistogram(string $namespace, string $name, string $help, array $labels = [], ?array $buckets = null): ?BetterHistogram
|
||||
{
|
||||
if (!$this->getSettings()->getPrometheus()->getEnableCollection()) {
|
||||
if (!$this->getSettings()->getMetrics()->getEnablePrometheusCollection()) {
|
||||
return null;
|
||||
}
|
||||
return GarbageCollector::$prometheus->getOrRegisterHistogram(
|
||||
@ -938,7 +940,7 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
'php_version' => PHP_VERSION,
|
||||
'madeline_version' => API::RELEASE,
|
||||
]);
|
||||
$endpoint = $this->getSettings()->getPrometheus()->getMetricsBindTo();
|
||||
$endpoint = $this->getSettings()->getMetrics()->getMetricsBindTo();
|
||||
$this->promServer?->stop();
|
||||
if ($endpoint === null) {
|
||||
$this->promServer = null;
|
||||
@ -955,12 +957,27 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
}
|
||||
public function handleRequest(ServerRequest $request): ServerResponse
|
||||
{
|
||||
if ($request->getUri()->getPath() === '/metrics') {
|
||||
return new ServerResponse(
|
||||
status: HttpStatus::OK,
|
||||
headers: ['Content-Type' => 'text/plain'],
|
||||
body: $this->API->renderPromStats(),
|
||||
);
|
||||
}
|
||||
if ($request->getUri()->getPath() === '/debug/pprof') {
|
||||
return new ServerResponse(
|
||||
status: HttpStatus::OK,
|
||||
headers: ['Content-Type' => 'text/plain'],
|
||||
body: $this->API->getMemoryProfile(),
|
||||
);
|
||||
}
|
||||
$result = ResponseInfo::error(HttpStatus::NOT_FOUND);
|
||||
return new ServerResponse(
|
||||
$result->getCode(),
|
||||
$result->getHeaders(),
|
||||
$result->getCodeExplanation()
|
||||
);
|
||||
}
|
||||
}, new DefaultErrorHandler);
|
||||
}
|
||||
$this->updateCtr = $this->getPromCounter("MadelineProto", "update_count", "Number of received updates since the session was created");
|
||||
@ -1317,10 +1334,10 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
$this->cleanupProperties();
|
||||
$this->settings->getDb()->applyChanges();
|
||||
}
|
||||
if ($this->settings->getPrometheus()->hasChanged()) {
|
||||
if ($this->settings->getMetrics()->hasChanged()) {
|
||||
$this->logger->logger("The prometheus settings have changed!", Logger::WARNING);
|
||||
$this->cleanupProperties();
|
||||
$this->settings->getPrometheus()->applyChanges();
|
||||
$this->settings->getMetrics()->applyChanges();
|
||||
}
|
||||
if ($this->settings->getSerialization()->hasChanged()) {
|
||||
$this->logger->logger("The serialization settings have changed!", Logger::WARNING);
|
||||
@ -1900,9 +1917,9 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Report memory profile with memprof.
|
||||
* Get memory profile with memprof.
|
||||
*/
|
||||
public function reportMemoryProfile(): void
|
||||
public function getMemoryProfile(): string
|
||||
{
|
||||
if (!\extension_loaded('memprof')) {
|
||||
throw Exception::extension('memprof');
|
||||
@ -1910,14 +1927,24 @@ final class MTProto implements TLCallback, LoggerGetter, SettingsGetter
|
||||
if (!memprof_enabled()) {
|
||||
throw new Exception("Memory profiling is not enabled, set the MEMPROF_PROFILE=1 environment variable or GET parameter to enable it.");
|
||||
}
|
||||
|
||||
$current = "Current memory usage: ".round(memory_get_usage()/1024/1024, 1) . " MB";
|
||||
$file = fopen('php://memory', 'r+');
|
||||
memprof_dump_pprof($file);
|
||||
fseek($file, 0);
|
||||
|
||||
return stream_get_contents($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report memory profile with memprof.
|
||||
*/
|
||||
public function reportMemoryProfile(): void
|
||||
{
|
||||
$pprof = $this->getMemoryProfile();
|
||||
|
||||
$current = "Current memory usage: ".round(memory_get_usage()/1024/1024, 1) . " MB";
|
||||
$file = [
|
||||
'_' => 'inputMediaUploadedDocument',
|
||||
'file' => $file,
|
||||
'file' => new ReadableBuffer($pprof),
|
||||
'attributes' => [
|
||||
['_' => 'documentAttributeFilename', 'file_name' => 'report.pprof'],
|
||||
],
|
||||
|
@ -49,6 +49,8 @@ final class ResponseInfo
|
||||
private int $code = HttpStatus::OK;
|
||||
/**
|
||||
* Header array.
|
||||
*
|
||||
* @var array<non-empty-string, string|list<string>>
|
||||
*/
|
||||
private array $headers = [];
|
||||
/**
|
||||
@ -124,7 +126,7 @@ final class ResponseInfo
|
||||
} elseif ($size > 0) {
|
||||
$this->headers['Content-Length'] = (string) $size;
|
||||
}
|
||||
$this->headers['Content-Type'] = $messageMedia['mime'];
|
||||
$this->headers['Content-Type'] = (string) $messageMedia['mime'];
|
||||
$this->headers['Cache-Control'] = 'max-age=31556926';
|
||||
$this->headers['Content-Transfer-Encoding'] = 'Binary';
|
||||
$this->headers['Accept-Ranges'] = 'bytes';
|
||||
@ -207,7 +209,7 @@ final class ResponseInfo
|
||||
/**
|
||||
* Get header array.
|
||||
*
|
||||
* @return array Header array
|
||||
* @return array<non-empty-string, string|list<string>> Header array
|
||||
*/
|
||||
public function getHeaders(): array
|
||||
{
|
||||
|
@ -24,8 +24,8 @@ use danog\MadelineProto\Settings\DatabaseAbstract;
|
||||
use danog\MadelineProto\Settings\Files;
|
||||
use danog\MadelineProto\Settings\Ipc;
|
||||
use danog\MadelineProto\Settings\Logger;
|
||||
use danog\MadelineProto\Settings\Metrics;
|
||||
use danog\MadelineProto\Settings\Peer;
|
||||
use danog\MadelineProto\Settings\Prometheus;
|
||||
use danog\MadelineProto\Settings\RPC;
|
||||
use danog\MadelineProto\Settings\SecretChats;
|
||||
use danog\MadelineProto\Settings\Serialization;
|
||||
@ -55,9 +55,9 @@ final class Settings extends SettingsAbstract
|
||||
*/
|
||||
protected Files $files;
|
||||
/**
|
||||
* Prometheus settings.
|
||||
* Metrics settings.
|
||||
*/
|
||||
protected Prometheus $prometheus;
|
||||
protected Metrics $metrics;
|
||||
/**
|
||||
* IPC server settings.
|
||||
*/
|
||||
@ -110,7 +110,7 @@ final class Settings extends SettingsAbstract
|
||||
$this->files = new Files;
|
||||
$this->logger = new Logger;
|
||||
$this->peer = new Peer;
|
||||
$this->prometheus = new Prometheus;
|
||||
$this->metrics = new Metrics;
|
||||
$this->rpc = new RPC;
|
||||
$this->secretChats = new SecretChats;
|
||||
$this->serialization = new Serialization;
|
||||
@ -125,8 +125,8 @@ final class Settings extends SettingsAbstract
|
||||
if (!isset($this->voip)) {
|
||||
$this->voip = new VoIP;
|
||||
}
|
||||
if (!isset($this->prometheus)) {
|
||||
$this->prometheus = new Prometheus;
|
||||
if (!isset($this->metrics)) {
|
||||
$this->metrics = new Metrics;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -145,8 +145,8 @@ final class Settings extends SettingsAbstract
|
||||
$this->connection->merge($settings);
|
||||
} elseif ($settings instanceof Files) {
|
||||
$this->files->merge($settings);
|
||||
} elseif ($settings instanceof Prometheus) {
|
||||
$this->prometheus->merge($settings);
|
||||
} elseif ($settings instanceof Metrics) {
|
||||
$this->metrics->merge($settings);
|
||||
} elseif ($settings instanceof Logger) {
|
||||
$this->logger->merge($settings);
|
||||
} elseif ($settings instanceof Peer) {
|
||||
@ -178,7 +178,7 @@ final class Settings extends SettingsAbstract
|
||||
$this->auth->merge($settings->auth);
|
||||
$this->connection->merge($settings->connection);
|
||||
$this->files->merge($settings->files);
|
||||
$this->prometheus->merge($settings->prometheus);
|
||||
$this->metrics->merge($settings->metrics);
|
||||
$this->logger->merge($settings->logger);
|
||||
$this->peer->merge($settings->peer);
|
||||
$this->rpc->merge($settings->rpc);
|
||||
@ -277,21 +277,21 @@ final class Settings extends SettingsAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prometheus settings.
|
||||
* Get metrics settings.
|
||||
*/
|
||||
public function getPrometheus(): Prometheus
|
||||
public function getMetrics(): Metrics
|
||||
{
|
||||
return $this->prometheus;
|
||||
return $this->metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set prometheus settings.
|
||||
* Set metrics settings.
|
||||
*
|
||||
* @param Prometheus $prometheus File management settings.
|
||||
* @param Metrics $metrics File management settings.
|
||||
*/
|
||||
public function setPrometheus(Prometheus $prometheus): self
|
||||
public function setMetrics(Metrics $metrics): self
|
||||
{
|
||||
$this->prometheus = $prometheus;
|
||||
$this->metrics = $metrics;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -20,25 +20,30 @@ use Amp\Socket\SocketAddress;
|
||||
use danog\MadelineProto\SettingsAbstract;
|
||||
|
||||
/**
|
||||
* Prometheus settings.
|
||||
* Metric settings.
|
||||
*/
|
||||
final class Prometheus extends SettingsAbstract
|
||||
final class Metrics extends SettingsAbstract
|
||||
{
|
||||
/**
|
||||
* Whether to enable prometheus stat collection for this session.
|
||||
* Whether to enable additional prometheus stat collection for this session.
|
||||
*/
|
||||
protected bool $enableCollection = false;
|
||||
protected bool $enablePrometheusCollection = false;
|
||||
/**
|
||||
* Whether to expose prometheus metrics on the specified endpoint via HTTP.
|
||||
* Whether to enable memprof memory stat collection for this session.
|
||||
*/
|
||||
protected bool $enableMemprofCollection = false;
|
||||
|
||||
/**
|
||||
* Whether to expose metrics on the specified endpoint via HTTP.
|
||||
*/
|
||||
protected ?SocketAddress $metricsBindTo = null;
|
||||
/**
|
||||
* Whether to expose prometheus metrics with startAndLoop, by providing a ?metrics query string.
|
||||
* Whether to expose metrics with startAndLoop, by providing a ?metrics or ?pprof query string.
|
||||
*/
|
||||
protected bool $returnMetricsFromStartAndLoop = false;
|
||||
|
||||
/**
|
||||
* Whether to expose prometheus metrics with startAndLoop, by providing a ?metrics query string.
|
||||
* Whether to expose prometheus/memprof metrics with startAndLoop, by providing a ?metrics or ?pprof query string.
|
||||
*/
|
||||
public function setReturnMetricsFromStartAndLoop(bool $enable): self
|
||||
{
|
||||
@ -46,7 +51,7 @@ final class Prometheus extends SettingsAbstract
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Whether to expose prometheus metrics with startAndLoop, by providing a ?metrics query string.
|
||||
* Whether to expose prometheus/memprof metrics with startAndLoop, by providing a ?metrics or ?pprof query string.
|
||||
*/
|
||||
public function getReturnMetricsFromStartAndLoop(): bool
|
||||
{
|
||||
@ -56,21 +61,37 @@ final class Prometheus extends SettingsAbstract
|
||||
/**
|
||||
* Whether to enable additional prometheus stat collection for this session.
|
||||
*/
|
||||
public function setEnableCollection(bool $enable): self
|
||||
public function setEnablePrometheusCollection(bool $enable): self
|
||||
{
|
||||
$this->enableCollection = $enable;
|
||||
$this->enablePrometheusCollection = $enable;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Whether additional prometheus stat collection is enabled for this session.
|
||||
*/
|
||||
public function getEnableCollection(): bool
|
||||
public function getEnablePrometheusCollection(): bool
|
||||
{
|
||||
return $this->enableCollection;
|
||||
return $this->enablePrometheusCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to expose prometheus metrics on the specified endpoint via HTTP.
|
||||
* Whether to enable memprof memory stat collection for this session.
|
||||
*/
|
||||
public function setEnableMemprofCollection(bool $enable): self
|
||||
{
|
||||
$this->enableMemprofCollection = $enable;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Whether to enable memprof memory stat collection for this session.
|
||||
*/
|
||||
public function getEnableMemprofCollection(): bool
|
||||
{
|
||||
return $this->enableMemprofCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to expose metrics on the specified endpoint via HTTP.
|
||||
*/
|
||||
public function setMetricsBindTo(?SocketAddress $metricsBindTo): self
|
||||
{
|
||||
@ -79,7 +100,7 @@ final class Prometheus extends SettingsAbstract
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to expose prometheus metrics on the specified endpoint via HTTP.
|
||||
* Whether to expose metrics on the specified endpoint via HTTP.
|
||||
*/
|
||||
public function getMetricsBindTo(): ?SocketAddress
|
||||
{
|
Loading…
x
Reference in New Issue
Block a user