Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new metric magento_products_by_type_count_total #42

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ The following metrics will be collected:
| magento_catalog_category_count_total | status, menu_status, store_code | gauge | Count of Categories by store, status and menu status. |
| magento_store_count_total | status | gauge | Total count of Stores by status. |
| magento_website_count_total | | gauge | Total count websites. |
| magento_products_by_type_count_total | project_type | gauge | Total count of products by type. |

## Add you own Metric

Expand Down
140 changes: 140 additions & 0 deletions Test/Unit/Aggregator/Product/ProductByTypeCountAggregatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

declare(strict_types=1);

namespace RunAsRoot\PrometheusExporter\Test\Unit\Aggregator\Product;

use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Select;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use RunAsRoot\PrometheusExporter\Aggregator\Product\ProductByTypeCountAggregator;
use RunAsRoot\PrometheusExporter\Api\Data\MetricInterface;
use RunAsRoot\PrometheusExporter\Repository\MetricRepository;
use RunAsRoot\PrometheusExporter\Service\UpdateMetricService;

final class ProductByTypeCountAggregatorTest extends TestCase
{
private const METRIC_CODE = 'magento_products_by_type_count_total';
private const TABLE_PRODUCT = 'm2_catalog_product_entity';

private ProductByTypeCountAggregator $subject;

private MetricRepository $metricRepository;

private SearchCriteriaBuilder $searchCriteriaBuilder;

private SearchCriteriaInterface $searchCriteria;

private MockObject|UpdateMetricService $updateMetricService;

private MockObject|ResourceConnection $resourceConnection;

protected function setUp(): void
{
$this->metricRepository = $this->createMock(MetricRepository::class);
$this->searchCriteriaBuilder = $this->createMock(SearchCriteriaBuilder::class);
$this->updateMetricService = $this->createMock(UpdateMetricService::class);
$this->resourceConnection = $this->createMock(ResourceConnection::class);
$this->searchCriteria = $this->createMock(SearchCriteriaInterface::class);

$this->searchCriteriaBuilder->method('create')->willReturn($this->searchCriteria);
$this->searchCriteriaBuilder
->expects($this->once())
->method('addFilter')
->with('code', self::METRIC_CODE)
->willReturnSelf();

$metric = $this->createMock(MetricInterface::class);
$metric->expects($this->once())
->method('setValue')
->with('0');

$searchResultsMock = $this->createMock(\Magento\Framework\Api\SearchResultsInterface::class);
$searchResultsMock->expects($this->once())
->method('getItems')
->willReturn([$metric]);

$this->metricRepository->expects($this->once())
->method('getList')
->with($this->searchCriteria)
->willReturn($searchResultsMock);

$this->metricRepository->expects($this->once())
->method('save')
->with($metric);

$this->subject = new ProductByTypeCountAggregator(
$this->metricRepository,
$this->searchCriteriaBuilder,
$this->updateMetricService,
$this->resourceConnection
);
}

private function getStatisticData(): array
{
return [
['PRODUCT_COUNT' => 111, 'PRODUCT_TYPE' => 'bundle'],
['PRODUCT_COUNT' => 222, 'PRODUCT_TYPE' => 'configurable'],
['PRODUCT_COUNT' => 333, 'PRODUCT_TYPE' => 'giftcard'],
['PRODUCT_COUNT' => 444, 'PRODUCT_TYPE' => 'grouped'],
['PRODUCT_COUNT' => 555, 'PRODUCT_TYPE' => 'simple'],
['PRODUCT_COUNT' => 666, 'PRODUCT_TYPE' => 'virtual']
];
}

private function getSelectMock(): MockObject
{
$select = $this->createMock(Select::class);
$select->expects($this->once())
->method('from')
->with(['p' => self::TABLE_PRODUCT])
->willReturn($select);

$select->expects($this->once())->method('reset')->with(Select::COLUMNS)->willReturn($select);
$select->expects($this->once())->method('group')->with(['p.type_id']);
$select->expects($this->once())
->method('columns')
->with(['PRODUCT_COUNT' => 'COUNT(*)', 'PRODUCT_TYPE' => 'p.type_id'])
->willReturn($select);

return $select;
}

public function testAggregate(): void
{
$connection = $this->createMock(AdapterInterface::class);
$statisticData = $this->getStatisticData();
$select = $this->getSelectMock();

$this->resourceConnection->expects($this->once())
->method('getConnection')
->with('products')
->willReturn($connection);

$connection->expects($this->once())->method('select')->willReturn($select);
$connection->method('getTableName')
->with('catalog_product_entity')
->willReturn(self::TABLE_PRODUCT);
$connection->expects($this->once())->method('fetchAll')->with($select)->willReturn($statisticData);

$params = [];
foreach ($statisticData as $data) {
$params[] = [
self::METRIC_CODE,
(string)$data['PRODUCT_COUNT'],
['product_type' => $data['PRODUCT_TYPE']]
];
}

$this->updateMetricService->expects($this->exactly(6))
->method('update')
->withConsecutive(...$params);

$this->subject->aggregate();
}
}
103 changes: 103 additions & 0 deletions src/Aggregator/Product/ProductByTypeCountAggregator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

declare(strict_types=1);

namespace RunAsRoot\PrometheusExporter\Aggregator\Product;

use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Select;
use RunAsRoot\PrometheusExporter\Api\Data\MetricInterface;
use RunAsRoot\PrometheusExporter\Api\MetricAggregatorInterface;
use RunAsRoot\PrometheusExporter\Repository\MetricRepository;
use RunAsRoot\PrometheusExporter\Service\UpdateMetricService;

class ProductByTypeCountAggregator implements MetricAggregatorInterface
{
private const METRIC_CODE = 'magento_products_by_type_count_total';

private MetricRepository $metricRepository;
private SearchCriteriaBuilder $searchCriteriaBuilder;
private UpdateMetricService $updateMetricService;
private ResourceConnection $resourceConnection;

public function __construct(
MetricRepository $metricRepository,
SearchCriteriaBuilder $searchCriteriaBuilder,
UpdateMetricService $updateMetricService,
ResourceConnection $resourceConnection
) {
$this->metricRepository = $metricRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->updateMetricService = $updateMetricService;
$this->resourceConnection = $resourceConnection;
}

public function getCode(): string
{
return self::METRIC_CODE;
}

public function getHelp(): string
{
return 'Magento 2 Product by type Count';
}

public function getType(): string
{
return 'gauge';
}

public function aggregate(): bool
{
$this->resetMetrics();

$connection = $this->resourceConnection->getConnection('products');
scolandrea marked this conversation as resolved.
Show resolved Hide resolved

$productSearchResult = $connection->fetchAll($this->getSelect($connection));

if (count($productSearchResult) === 0) {
return true;
}

foreach ($productSearchResult as $result) {
$count = $result['PRODUCT_COUNT'] ?? 0;
$productType = $result['PRODUCT_TYPE'] ?? '';

$labels = ['product_type' => $productType];

$this->updateMetricService->update(self::METRIC_CODE, (string)$count, $labels);
}

return true;
}


protected function resetMetrics(): void
{
$searchCriteriaMetrics = $this->searchCriteriaBuilder->addFilter('code', self::METRIC_CODE)->create();
$metricsSearchResult = $this->metricRepository->getList($searchCriteriaMetrics);
$metrics = $metricsSearchResult->getItems();
/** @var MetricInterface $metric */
foreach ($metrics as $metric) {
$metric->setValue("0");
$this->metricRepository->save($metric);
}
}

private function getSelect(AdapterInterface $connection): Select
{
$select = $connection->select();

$select->from(['p' => $connection->getTableName('catalog_product_entity')])
->reset(Select::COLUMNS)->columns(
[
'PRODUCT_COUNT' => 'COUNT(*)',
'PRODUCT_TYPE' => 'p.type_id'
]
)->group(['p.type_id']);

return $select;
}
}
1 change: 1 addition & 0 deletions src/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

<!-- Product Aggregator -->
<item name="ProductCountAggregator" xsi:type="object">RunAsRoot\PrometheusExporter\Aggregator\Product\ProductCountAggregator</item>
<item name="ProductByTypeCountAggregator" xsi:type="object">RunAsRoot\PrometheusExporter\Aggregator\Product\ProductByTypeCountAggregator</item>

<!-- Shipping Aggregator -->
<item name="ActiveShippingMethodsCountAggregator" xsi:type="object">RunAsRoot\PrometheusExporter\Aggregator\Shipping\ActiveShippingMethodsCountAggregator</item>
Expand Down