├── Api
└── Data
│ └── LogInterface.php
├── Console
└── Command
│ └── CleanCommand.php
├── Controller
└── Adminhtml
│ └── Reports
│ ├── Delete.php
│ ├── Detail.php
│ └── Index.php
├── Cron
└── CleanCron.php
├── LICENSE
├── Model
├── Clean.php
├── Config.php
├── Config
│ └── Source
│ │ ├── Code.php
│ │ ├── Methods.php
│ │ └── RequestorIp.php
├── Log.php
├── Log
│ └── Logger.php
├── LogHandle.php
├── ResourceModel
│ ├── Entity
│ │ └── LogCollection.php
│ └── LogResourceModel.php
└── SecretParser.php
├── Plugin
├── FrontControllerDispatchAfter.php
└── FrontControllerDispatchBefore.php
├── README.md
├── Ui
├── Component
│ └── Listing
│ │ └── Column
│ │ ├── Datetime.php
│ │ └── RowAction.php
└── DataProvider
│ └── LogListingDataProvider.php
├── ViewModel
└── Detail.php
├── composer.json
├── etc
├── acl.xml
├── adminhtml
│ ├── menu.xml
│ ├── routes.xml
│ └── system.xml
├── config.xml
├── crontab.xml
├── db_schema.xml
├── di.xml
└── module.xml
├── registration.php
├── screenshots
├── screen1.png
├── screen2.png
├── screen3.png
└── screen4.png
└── view
└── adminhtml
├── layout
├── webapi_logs_reports_detail.xml
└── webapi_logs_reports_index.xml
├── templates
└── detail.phtml
├── ui_component
└── webapi_logs_reports_index_listing.xml
└── web
├── js
├── grid
│ └── columns
│ │ └── select.js
└── js-beautify
│ └── beautify.min.js
└── template
└── ui
└── grid
└── cells
└── text.html
/Api/Data/LogInterface.php:
--------------------------------------------------------------------------------
1 | clean = $clean;
32 | parent::__construct($name);
33 | }
34 |
35 | /**
36 | * @inheritDoc
37 | */
38 | protected function configure()
39 | {
40 | $this->setDescription('WebapiLogs Cleaner');
41 | parent::configure();
42 | }
43 |
44 | /**
45 | * @param InputInterface $input
46 | * @param OutputInterface $output
47 | * @throws \Exception
48 | */
49 | protected function execute(InputInterface $input, OutputInterface $output)
50 | {
51 | $this->clean->execute();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Reports/Delete.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
55 | $this->logCollectionFactory = $logCollectionFactory;
56 | $this->logger = $logger;
57 | }
58 |
59 | /**
60 | * @inheritDoc
61 | */
62 | public function execute()
63 | {
64 | try {
65 | $logs = $this->logCollectionFactory->create();
66 | foreach ($logs as $log) {
67 | $log->delete();
68 | }
69 | } catch (Exception $exception) {
70 | $this->logger->error(__('Cant delete webapi log because of error: %1', $exception->getMessage()));
71 | }
72 |
73 | $resultRedirect = $this->resultRedirectFactory->create();
74 | return $resultRedirect->setPath('*/*/index', ['_current' => true]);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Reports/Detail.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
40 | }
41 |
42 | /**
43 | * @return Page|ResultInterface
44 | */
45 | public function execute()
46 | {
47 | $resultPage = $this->resultPageFactory->create();
48 | $resultPage->setActiveMenu('GhostUnicorns_WebapiLogs::reports');
49 | $resultPage->getConfig()->getTitle()->prepend(__('Webapi REST api logs'));
50 | return $resultPage;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Reports/Index.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
40 | }
41 |
42 | /**
43 | * @return Page|ResultInterface
44 | */
45 | public function execute()
46 | {
47 | $resultPage = $this->resultPageFactory->create();
48 | $resultPage->setActiveMenu('GhostUnicorns_WebapiLogs::reports');
49 | $resultPage->getConfig()->getTitle()->prepend(__('Webapi REST api logs'));
50 | return $resultPage;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Cron/CleanCron.php:
--------------------------------------------------------------------------------
1 | clean = $clean;
28 | }
29 |
30 | /**
31 | * @throws Exception
32 | */
33 | public function execute()
34 | {
35 | $this->clean->execute();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ghost Unicorns snc di Ugolini Riccardo e Argentiero Danilo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Model/Clean.php:
--------------------------------------------------------------------------------
1 | config = $config;
52 | $this->logger = $logger;
53 | $this->logCollectionFactory = $logCollectionFactory;
54 | $this->logResourceModel = $logResourceModel;
55 | }
56 |
57 | /**
58 | * @throws Exception
59 | */
60 | public function execute()
61 | {
62 | if (!$this->config->isEnabled()) {
63 | return;
64 | }
65 |
66 | $this->logger->info(__('Start webapi logs clean'));
67 | $hours = $this->config->getCleanOlderThanHours();
68 | $datetime = new DateTime('-' . $hours . ' hour');
69 | $page = 1;
70 |
71 | $collection = $this->logCollectionFactory->create();
72 | $collection = $collection->addFieldToSelect(LogResourceModel::LOG_ID)
73 | ->addFieldToFilter(LogResourceModel::CREATED_AT, ['lt' => $datetime])
74 | ->setPageSize(1000);
75 |
76 | $pageCount = $collection->getLastPageNumber();
77 | $currentPage = 1;
78 | $tot = 0;
79 | while ($currentPage <= $pageCount) {
80 | $collection->setCurPage($currentPage);
81 | foreach ($collection as $row) {
82 | $this->logResourceModel->delete($row);
83 | $tot++;
84 | }
85 | $collection->clear();
86 | $currentPage++;
87 | }
88 |
89 | $this->logger->info(__('End webapi logs clean. Deleted %1 elements.', $tot));
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Model/Config.php:
--------------------------------------------------------------------------------
1 | scopeConfig = $scopeConfig;
55 | }
56 |
57 | /**
58 | * @return bool
59 | */
60 | public function isEnabled(): bool
61 | {
62 | return $this->scopeConfig->isSetFlag(
63 | self::WEBAPI_LOGS_IS_ENABLED_CONFIG_PATH,
64 | ScopeInterface::SCOPE_WEBSITE
65 | );
66 | }
67 |
68 | public function isAjaxCallsDisabled(): bool
69 | {
70 | return $this->scopeConfig->isSetFlag(
71 | self::WEBAPI_LOGS_DISABLED_AJAX_CALLS,
72 | ScopeInterface::SCOPE_WEBSITE
73 | );
74 | }
75 |
76 |
77 | /**
78 | * @return bool
79 | */
80 | public function isSecretMode(): bool
81 | {
82 | return $this->scopeConfig->isSetFlag(
83 | self::WEBAPI_LOGS_LOG_SECRET_MODE,
84 | ScopeInterface::SCOPE_WEBSITE
85 | );
86 | }
87 |
88 | /**
89 | * @return array
90 | */
91 | public function getSecrets(): array
92 | {
93 | $secrets = $this->scopeConfig->getValue(
94 | self::WEBAPI_LOGS_LOG_SECRET_WORDS,
95 | ScopeInterface::SCOPE_WEBSITE
96 | );
97 | return preg_split('/\n|\r\n?/', $secrets);
98 | }
99 |
100 | /**
101 | * @return int
102 | */
103 | public function getCleanOlderThanHours(): int
104 | {
105 | return (int)$this->scopeConfig->getValue(
106 | self::WEBAPI_LOGS_LOG_CLEAN_OLDER_THAN_HOURS,
107 | ScopeInterface::SCOPE_WEBSITE
108 | );
109 | }
110 |
111 | /**
112 | * @return array
113 | */
114 | public function getFilterRequestPaths(): array
115 | {
116 | $value = $this->scopeConfig->getValue(
117 | self::WEBAPI_LOGS_LOG_FILTER_REQUEST_PATHS,
118 | ScopeInterface::SCOPE_WEBSITE
119 | );
120 | if ($value == null) {
121 | return [];
122 | }
123 | return preg_split('/\n|\r\n?/', $value);
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/Model/Config/Source/Code.php:
--------------------------------------------------------------------------------
1 | logCollectionFactory = $logCollectionFactory;
29 | }
30 |
31 | /**
32 | * @return array
33 | */
34 | public function toOptionArray(): array
35 | {
36 | $result = [];
37 | /** @var LogCollection $logsCollection */
38 | $logsCollection = $this->logCollectionFactory->create();
39 | $logsCollection->addFieldToSelect('response_code');
40 | $logsCollection->distinct(true);
41 | foreach ($logsCollection as $logs) {
42 | $result[] = [
43 | 'value' => $logs->getResponseCode(),
44 | 'label' => $logs->getResponseCode()
45 | ];
46 | }
47 | return $result;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Model/Config/Source/Methods.php:
--------------------------------------------------------------------------------
1 | logCollectionFactory = $logCollectionFactory;
29 | }
30 |
31 | /**
32 | * @return array
33 | */
34 | public function toOptionArray(): array
35 | {
36 | $result = [];
37 | /** @var LogCollection $logsCollection */
38 | $logsCollection = $this->logCollectionFactory->create();
39 | $logsCollection->addFieldToSelect('request_method');
40 | $logsCollection->distinct(true);
41 | foreach ($logsCollection as $logs) {
42 | $result[] = [
43 | 'value' => $logs->getRequestMethod(),
44 | 'label' => $logs->getRequestMethod()
45 | ];
46 | }
47 | return $result;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Model/Config/Source/RequestorIp.php:
--------------------------------------------------------------------------------
1 | logCollectionFactory = $logCollectionFactory;
29 | }
30 |
31 | /**
32 | * @return array
33 | */
34 | public function toOptionArray(): array
35 | {
36 | $result = [];
37 | /** @var LogCollection $logsCollection */
38 | $logsCollection = $this->logCollectionFactory->create();
39 | $logsCollection->addFieldToSelect('requestor_ip');
40 | $logsCollection->distinct(true);
41 | foreach ($logsCollection as $logs) {
42 | $result[] = [
43 | 'value' => $logs->getRequestorIp(),
44 | 'label' => $logs->getRequestorIp()
45 | ];
46 | }
47 | return $result;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Model/Log.php:
--------------------------------------------------------------------------------
1 | _init(LogResourceModel::class);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Model/Log/Logger.php:
--------------------------------------------------------------------------------
1 | logFactory = $logFactory;
59 | $this->logResourceModel = $logResourceModel;
60 | $this->config = $config;
61 | $this->logger = $logger;
62 | $this->secretParser = $secretParser;
63 | }
64 |
65 | /**
66 | * @param string $requestMethod
67 | * @param string $requestorIp
68 | * @param string $requestPath
69 | * @param string $requestHeaders
70 | * @param string $requestBody
71 | * @param string $requestDateTime
72 | */
73 | public function before(
74 | string $requestMethod,
75 | string $requestorIp,
76 | string $requestPath,
77 | string $requestHeaders,
78 | string $requestBody,
79 | string $requestDateTime
80 | ) {
81 | $filter = $this->config->getFilterRequestPaths();
82 |
83 | // Only log this request if the path is not filtered.
84 | if (!$this->filterRequestPath($requestPath, $filter)) {
85 | if ($this->config->isSecretMode()) {
86 | $requestorIp = $this->secretParser->parseIp();
87 | $requestHeaders = $this->secretParser->parseHeades($requestHeaders);
88 | $requestBody = $this->secretParser->parseBody($requestBody);
89 | }
90 |
91 | $log = $this->logFactory->create();
92 | $log->setData([
93 | 'request_method' => $requestMethod,
94 | 'requestor_ip' => $requestorIp,
95 | 'request_url' => $requestPath,
96 | 'request_headers' => $requestHeaders,
97 | 'request_body' => $requestBody,
98 | 'request_datetime' => $requestDateTime
99 | ]);
100 | $this->lastLog = $log;
101 | }
102 | }
103 |
104 | /**
105 | * @param string $responseCode
106 | * @param string $resposeBody
107 | * @param string $responseDateTime
108 | */
109 | public function after(
110 | string $responseCode,
111 | string $resposeBody,
112 | string $responseDateTime
113 | ) {
114 | if (!$this->lastLog) {
115 | return;
116 | }
117 |
118 | try {
119 | if ($this->config->isSecretMode()) {
120 | $resposeBody = $this->secretParser->parseBody($resposeBody);
121 | }
122 |
123 | $this->lastLog->setResponseBody($resposeBody);
124 | $this->lastLog->setResponseCode($responseCode);
125 | $this->lastLog->setResponseDatetime($responseDateTime);
126 | $this->logResourceModel->save($this->lastLog);
127 | } catch (Exception $exception) {
128 | $this->logger->error(__('Cant complete webapi log save because of error: %1', $exception->getMessage()));
129 | }
130 | }
131 |
132 | /**
133 | * Check if request path is among the filters.
134 | *
135 | * @param string $requestPath
136 | * @param array $filters
137 | *
138 | * @return bool
139 | */
140 | private function filterRequestPath(
141 | string $requestPath,
142 | array $filters
143 | ): bool {
144 | foreach ($filters as $filter) {
145 | if ($filter != '') {
146 | if (stripos($requestPath, $filter) !== false) {
147 | return true;
148 | }
149 | }
150 | }
151 | return false;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/Model/ResourceModel/Entity/LogCollection.php:
--------------------------------------------------------------------------------
1 | _init(Log::class, LogResourceModel::class);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Model/ResourceModel/LogResourceModel.php:
--------------------------------------------------------------------------------
1 | _init('webapi_logs', 'log_id');
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Model/SecretParser.php:
--------------------------------------------------------------------------------
1 | config = $config;
25 | }
26 |
27 | /**
28 | * @return string
29 | */
30 | public function parseIp(): string
31 | {
32 | return '***.***.***.***';
33 | }
34 |
35 | /**
36 | * @param string $header
37 | * @return string
38 | */
39 | public function parseHeades(string $header): string
40 | {
41 | $secrets = $this->config->getSecrets();
42 | $headers = implode('|', $secrets);
43 | return preg_replace('/('.$headers.'):(.*)/', '$1: ********', $header);
44 | }
45 |
46 | /**
47 | * @param string $body
48 | * @return string
49 | */
50 | public function parseBody(string $body): string
51 | {
52 | $secrets = $this->config->getSecrets();
53 | foreach ($secrets as $secret) {
54 | $body = preg_replace('/' . $secret . '(")*:( )*"(.*)"/', $secret . '$1: "********"', $body);
55 | }
56 | return $body;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Plugin/FrontControllerDispatchAfter.php:
--------------------------------------------------------------------------------
1 | config = $config;
45 | $this->date = $date;
46 | $this->logHandle = $logHandle;
47 | }
48 |
49 | /**
50 | * @param Rest $subject
51 | * @param $result
52 | * @param RequestInterface $request
53 | * @return mixed
54 | */
55 | public function afterDispatch(Rest $subject, $result, RequestInterface $request)
56 | {
57 | if ($this->config->isEnabled()
58 | && (
59 | !$request->isXmlHttpRequest()
60 | || !$this->config->isAjaxCallsDisabled()
61 | )
62 | ) {
63 | $exceptions = $result->getException();
64 |
65 | if (!empty($exceptions)) {
66 | $responseCode = '';
67 | $resposeBody = '';
68 | foreach ($exceptions as $exception) {
69 | $responseCode .= (string)$exception->getHttpCode() . ' ';
70 | $resposeBody .= $exception->getMessage() . ' ';
71 | }
72 | $responseCode = rtrim($responseCode);
73 | $resposeBody = rtrim($resposeBody);
74 | } else {
75 | $responseCode = (string)$result->getStatusCode();
76 | $resposeBody = $result->getContent();
77 | $resposeBody = trim($resposeBody, '"');
78 | }
79 |
80 | $responseDateTime = $this->date->gmtDate();
81 | $this->logHandle->after($responseCode, $resposeBody, $responseDateTime);
82 | }
83 | return $result;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Plugin/FrontControllerDispatchBefore.php:
--------------------------------------------------------------------------------
1 | config = $config;
45 | $this->date = $date;
46 | $this->logHandle = $logHandle;
47 | }
48 |
49 | /**
50 | * @param Rest $subject
51 | * @param RequestInterface $request
52 | * @return array
53 | */
54 | public function beforeDispatch(Rest $subject, RequestInterface $request)
55 | {
56 | if ($this->config->isEnabled()
57 | && (
58 | !$request->isXmlHttpRequest()
59 | || !$this->config->isAjaxCallsDisabled()
60 | )
61 | ) {
62 | $requestMethod = $request->getMethod();
63 | $requestorIp = $request->getClientIp();
64 | $requestPath = $request->getUriString();
65 | $requestHeaders = $request->getHeaders()->toString();
66 | $requestBody = $request->getContent();
67 | $requestDateTime = $this->date->gmtDate();
68 |
69 | $this->logHandle->before(
70 | $requestMethod,
71 | $requestorIp,
72 | $requestPath,
73 | $requestHeaders,
74 | $requestBody,
75 | $requestDateTime
76 | );
77 | }
78 | return [$request];
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Description
2 |
3 | This module allows you to analyze all the webapi rest done call toward your magento.
4 |
5 | # Install
6 |
7 | `composer require youwe/module-webapi-logs`
8 |
9 | # Configure
10 |
11 | 1. Log-in your Magento backend
12 |
13 | 2. Go to `Stores > Configuration > System > Webapi Logs` and enable it
14 |
15 |
16 |
17 | # Use
18 |
19 | Go to `Reports > Webapi Logs > Show Logs`
20 |
21 |
22 |
23 | You can select an entry to see more details about the request and the response
24 |
25 |
26 |
27 | # Attention!
28 |
29 | If you disable the Secret Mode this module will logs everything passes in the webapi calls (tokens and passwords too!), then remember to clean logs by clicking the `Delete All Logs` button:
30 |
31 |
32 |
33 | # Contribution
34 |
35 | Yes, of course you can contribute sending a pull request to propose improvements and fixes.
36 |
37 |
--------------------------------------------------------------------------------
/Ui/Component/Listing/Column/Datetime.php:
--------------------------------------------------------------------------------
1 | timezone = $timezone;
74 | $this->booleanUtils = $booleanUtils;
75 | $this->localeResolver = $localeResolver ?? ObjectManager::getInstance()->get(ResolverInterface::class);
76 | $this->locale = $this->localeResolver->getLocale();
77 | $this->dataBundle = $dataBundle ?? ObjectManager::getInstance()->get(DataBundle::class);
78 | parent::__construct($context, $uiComponentFactory, $components, $data);
79 | }
80 |
81 | /**
82 | * @inheritdoc
83 | * @since 101.1.1
84 | */
85 | public function prepare()
86 | {
87 | $config = $this->getData('config');
88 | if (isset($config['filter'])) {
89 | $config['filter'] = [
90 | 'filterType' => 'dateRange',
91 | 'templates' => [
92 | 'date' => [
93 | 'options' => [
94 | 'dateFormat' => 'yyyy-MM-dd',
95 | 'showsTime' => true,
96 | 'timeFormat' => 'H:mm:ss',
97 | ]
98 | ]
99 | ]
100 | ];
101 | }
102 |
103 | $localeData = $this->dataBundle->get($this->locale);
104 | /** @var ResourceBundle $monthsData */
105 | $monthsData = $localeData['calendar']['gregorian']['monthNames'];
106 | $months = array_values(iterator_to_array($monthsData['format']['wide']));
107 | $monthsShort = array_values(
108 | iterator_to_array(
109 | null !== $monthsData->get('format')->get('abbreviated')
110 | ? $monthsData['format']['abbreviated']
111 | : $monthsData['format']['wide']
112 | )
113 | );
114 |
115 | $config['storeLocale'] = $this->locale;
116 | $config['calendarConfig'] = [
117 | 'months' => $months,
118 | 'monthsShort' => $monthsShort,
119 | ];
120 | if (!isset($config['dateFormat'])) {
121 | $config['dateFormat'] = 'yyyy-MM-dd H:mm:ss';
122 | }
123 | $config['options']['showsTime'] = true;
124 | $this->setData('config', $config);
125 |
126 | parent::prepare();
127 | }
128 |
129 | /**
130 | * @inheritdoc
131 | */
132 | public function prepareDataSource(array $dataSource)
133 | {
134 | if (isset($dataSource['data']['items'])) {
135 | foreach ($dataSource['data']['items'] as & $item) {
136 | if (isset($item[$this->getData('name')])
137 | && $item[$this->getData('name')] !== "0000-00-00 00:00:00"
138 | ) {
139 | $date = $this->timezone->date(new \DateTime($item[$this->getData('name')]));
140 | $item[$this->getData('name')] = $date->format('Y-m-d H:i:s');
141 | }
142 | }
143 | }
144 |
145 | return $dataSource;
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/Ui/Component/Listing/Column/RowAction.php:
--------------------------------------------------------------------------------
1 | urlBuilder = $urlBuilder;
38 | parent::__construct($context, $uiComponentFactory, $components, $data);
39 | }
40 |
41 | /**
42 | * @param array $dataSource
43 | * @return array
44 | */
45 | public function prepareDataSource(array $dataSource): array
46 | {
47 | if (isset($dataSource['data']['items'])) {
48 | foreach ($dataSource['data']['items'] as &$item) {
49 | $item[$this->getData('name')]['edit'] = [
50 | 'href' =>
51 | $this->urlBuilder->getUrl(
52 | 'webapi_logs/reports/detail',
53 | ['log_id' => $item['log_id']]
54 | ),
55 | 'label' => __('View More'),
56 | 'hidden' => false
57 | ];
58 | }
59 | }
60 |
61 | return $dataSource;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Ui/DataProvider/LogListingDataProvider.php:
--------------------------------------------------------------------------------
1 | request = $request;
101 | $this->filterBuilder = $filterBuilder;
102 | $this->name = $name;
103 | $this->primaryFieldName = $primaryFieldName;
104 | $this->requestFieldName = $requestFieldName;
105 | $this->reporting = $reporting;
106 | $this->searchCriteriaBuilder = $searchCriteriaBuilder;
107 | $this->meta = $meta;
108 | $this->data = $data;
109 | $this->prepareUpdateUrl();
110 | }
111 |
112 | /**
113 | * Get Data Provider name
114 | *
115 | * @return string
116 | */
117 | public function getName(): string
118 | {
119 | return $this->name;
120 | }
121 |
122 | /**
123 | * Get primary field name
124 | *
125 | * @return string
126 | */
127 | public function getPrimaryFieldName(): string
128 | {
129 | return $this->primaryFieldName;
130 | }
131 |
132 | /**
133 | * Get field name in request
134 | *
135 | * @return string
136 | */
137 | public function getRequestFieldName(): string
138 | {
139 | return $this->requestFieldName;
140 | }
141 |
142 | /**
143 | * @return array
144 | */
145 | public function getMeta(): array
146 | {
147 | return $this->meta;
148 | }
149 |
150 | /**
151 | * Get field Set meta info
152 | *
153 | * @param string $fieldSetName
154 | * @return array
155 | */
156 | public function getFieldSetMetaInfo($fieldSetName): array
157 | {
158 | return $this->meta[$fieldSetName] ?? [];
159 | }
160 |
161 | /**
162 | * @param string $fieldSetName
163 | * @return array
164 | */
165 | public function getFieldsMetaInfo($fieldSetName): array
166 | {
167 | return $this->meta[$fieldSetName]['children'] ?? [];
168 | }
169 |
170 | /**
171 | * @param string $fieldSetName
172 | * @param string $fieldName
173 | * @return array
174 | */
175 | public function getFieldMetaInfo($fieldSetName, $fieldName): array
176 | {
177 | return $this->meta[$fieldSetName]['children'][$fieldName] ?? [];
178 | }
179 |
180 | /**
181 | * @inheritdoc
182 | */
183 | public function addFilter(Filter $filter)
184 | {
185 | $this->searchCriteriaBuilder->addFilter($filter);
186 | }
187 |
188 | /**
189 | * self::setOrder() alias
190 | *
191 | * @param string $field
192 | * @param string $direction
193 | * @return void
194 | */
195 | public function addOrder($field, $direction)
196 | {
197 | $this->searchCriteriaBuilder->addSortOrder($field, $direction);
198 | }
199 |
200 | /**
201 | * Set Query limit
202 | *
203 | * @param int $offset
204 | * @param int $size
205 | * @return void
206 | */
207 | public function setLimit($offset, $size)
208 | {
209 | $this->searchCriteriaBuilder->setPageSize($size);
210 | $this->searchCriteriaBuilder->setCurrentPage($offset);
211 | }
212 |
213 | /**
214 | * @param SearchResultInterface $searchResult
215 | * @return array
216 | */
217 | protected function searchResultToOutput(SearchResultInterface $searchResult): array
218 | {
219 | $arrItems = [];
220 |
221 | $arrItems['items'] = [];
222 | foreach ($searchResult->getItems() as $item) {
223 | $itemData = [];
224 | foreach ($item->getCustomAttributes() as $attribute) {
225 | $itemData[$attribute->getAttributeCode()] = $attribute->getValue();
226 | }
227 | $arrItems['items'][] = $itemData;
228 | }
229 |
230 | $arrItems['totalRecords'] = $searchResult->getTotalCount();
231 |
232 | return $arrItems;
233 | }
234 |
235 | /**
236 | * Returns search criteria
237 | *
238 | * @return SearchCriteria
239 | */
240 | public function getSearchCriteria(): SearchCriteria
241 | {
242 | if (!isset($this->searchCriteria)) {
243 | $this->searchCriteria = $this->searchCriteriaBuilder->create();
244 | $this->searchCriteria->setRequestName($this->name);
245 | }
246 | return $this->searchCriteria;
247 | }
248 |
249 | /**
250 | * Get data
251 | *
252 | * @return array
253 | */
254 | public function getData(): array
255 | {
256 | return $this->searchResultToOutput($this->getSearchResult());
257 | }
258 |
259 | /**
260 | * Get config data
261 | *
262 | * @return array
263 | */
264 | public function getConfigData(): array
265 | {
266 | return $this->data['config'] ?? [];
267 | }
268 |
269 | /**
270 | * Set data
271 | *
272 | * @param mixed $config
273 | * @return void
274 | */
275 | public function setConfigData($config)
276 | {
277 | $this->data['config'] = $config;
278 | }
279 |
280 | /**
281 | * Returns Search result
282 | *
283 | * @return SearchResultInterface
284 | */
285 | public function getSearchResult(): SearchResultInterface
286 | {
287 | return $this->reporting->search($this->getSearchCriteria());
288 | }
289 |
290 | protected function prepareUpdateUrl()
291 | {
292 | if (!isset($this->data['config']['filter_url_params'])) {
293 | return;
294 | }
295 | foreach ($this->data['config']['filter_url_params'] as $paramName => $paramValue) {
296 | if ('*' == $paramValue) {
297 | $paramValue = $this->request->getParam($paramName);
298 | }
299 | if ($paramValue) {
300 | $this->data['config']['update_url'] = sprintf(
301 | '%s%s/%s/',
302 | $this->data['config']['update_url'],
303 | $paramName,
304 | $paramValue
305 | );
306 | $this->addFilter(
307 | $this->filterBuilder->setField($paramName)->setValue($paramValue)->setConditionType('eq')->create()
308 | );
309 | }
310 | }
311 | }
312 | }
313 |
--------------------------------------------------------------------------------
/ViewModel/Detail.php:
--------------------------------------------------------------------------------
1 | logResourceModel = $logResourceModel;
47 | $this->logFactory = $logFactory;
48 | $this->request = $request;
49 | }
50 |
51 | public function getLog()
52 | {
53 | $logId = $this->request->getParam('log_id');
54 |
55 | $log = $this->logFactory->create();
56 | $this->logResourceModel->load($log, $logId);
57 |
58 | return $log;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "youwe/module-webapi-logs",
3 | "description": "Magento Webapi Log Details accessible via backend",
4 | "type": "magento2-module",
5 | "require": {
6 | "magento/framework": "*",
7 | "magento/module-webapi": "*"
8 | },
9 | "authors": [
10 | {
11 | "name": "Danilo Argentiero",
12 | "email": "argentiero.danilo@gmail.com",
13 | "homepage": "https://www.linkedin.com/in/daniloargentiero/",
14 | "role": "Software Architect"
15 | },
16 | {
17 | "name": "Riccardo Ugolini",
18 | "email": "riccardo.ugolini@gmail.com",
19 | "homepage": "https://www.linkedin.com/in/riccardougolini/",
20 | "role": "Software Architect"
21 | }
22 | ],
23 | "license": [
24 | "MIT"
25 | ],
26 | "autoload": {
27 | "files": [
28 | "registration.php"
29 | ],
30 | "psr-4": {
31 | "GhostUnicorns\\WebapiLogs\\": ""
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/etc/acl.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
31 |
requestor_ip:
26 |= $log->getData('requestor_ip') ?>
27 |request_url:
29 |= $log->getData('request_url') ?>
30 |request_method:
32 |= $log->getData('request_method') ?>
33 |request_body:
35 |= $log->getData('request_body') ?>
36 |request_headers:
38 |= $log->getData('request_headers') ?>
39 |response_code:
42 |= $log->getData('response_code') ?>
43 |response_body:
45 |= $log->getData('response_body') ?>
46 |request_datetime:
48 |= $log->getData('request_datetime') ?>
49 |response_datetime:
51 |= $log->getData('response_datetime') ?>
52 |created_at:
54 |= $log->getData('created_at') ?>
55 |