Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
AccessLogManager
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 3
132
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 put
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 vacuum
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\App\Models\Domain;
6
7use DateTimeImmutable;
8use PeServer\App\Models\AppConfiguration;
9use PeServer\App\Models\Dao\Entities\AccessLogsEntityDao;
10use PeServer\App\Models\Data\Dto\AccessLogDto;
11use PeServer\Core\Binary;
12use PeServer\Core\Collection\Arr;
13use PeServer\Core\Database\IDatabaseConnection;
14use PeServer\Core\IO\Directory;
15use PeServer\Core\IO\File;
16use PeServer\Core\IO\Path;
17use PeServer\Core\Log\ILogger;
18use PeServer\Core\Log\ILoggerFactory;
19use PeServer\Core\Log\Logging;
20use PeServer\Core\Serialization\JsonSerializer;
21use PeServer\Core\Store\SpecialStore;
22use PeServer\Core\Text;
23
24class AccessLogManager
25{
26    #region variable
27
28    private ILogger $logger;
29
30    #endregion
31
32    public function __construct(
33        private IDatabaseConnection $databaseConnection,
34        private AppConfiguration $appConfig,
35        private SpecialStore $specialStore,
36        private Logging $logging,
37        ILoggerFactory $loggerFactory
38    ) {
39        $this->logger = $loggerFactory->createLogger($this);
40    }
41
42    #region function
43
44    public function put(): void
45    {
46        $jsonSerializer = new JsonSerializer(JsonSerializer::SAVE_NONE, JsonSerializer::LOAD_NONE);
47
48        $filePath = Path::combine($this->appConfig->setting->accessLog->directory, date('Ymd') . '.log');
49        Directory::createParentDirectoryIfNotExists($filePath);
50
51        $logParams = $this->logging->getLogParameters(new DateTimeImmutable(), $this->specialStore);
52        $logParams["RUNNING_TIME"] = microtime(true) - $this->specialStore->getServer('REQUEST_TIME_FLOAT', 0.0);
53
54        $data = $jsonSerializer->save($logParams);
55        $log = new Binary($data . PHP_EOL);
56        //$this->logger->trace("{0}", $data);
57        File::appendContent($filePath, $log);
58    }
59
60    public function vacuum(): void
61    {
62        $jsonSerializer = new JsonSerializer(JsonSerializer::SAVE_NONE, JsonSerializer::LOAD_NONE);
63
64        $files = Directory::find($this->appConfig->setting->accessLog->directory, "*.log");
65        /** @var Binary[] */
66        $contents = [];
67        foreach ($files as $file) {
68            $contents[] = File::readContent($file);
69            $this->logger->info('アクセスログ削除: {0}', $file);
70            File::removeFile($file);
71        }
72
73        /** @var AccessLogDto[] */
74        $accessLogs = [];
75        foreach ($contents as $content) {
76            $lines = Text::splitLines($content->raw);
77            foreach ($lines as $line) {
78                if (Text::isNullOrWhiteSpace($line)) {
79                    continue;
80                }
81
82                $raw = $jsonSerializer->load(new Binary($line));
83                assert(is_array($raw));
84
85                $request = $raw['REQUEST'];
86                $pqf = Text::split($request, '?', 2);
87                $p = $pqf[0];
88                $q = $f = '';
89                if (count($pqf) === 2) {
90                    $qf = Text::split($pqf[1], '#', 2);
91                    $q = $qf[0];
92                    if (count($qf) === 2) {
93                        $f = $qf[1];
94                    }
95                }
96
97                $dto = new AccessLogDto();
98                $dto->timestamp = $raw['TIMESTAMP'];
99                $dto->clientIp = $raw['CLIENT_IP'];
100                $dto->clientHost = $raw['CLIENT_HOST'];
101                $dto->requestId = $raw['REQUEST_ID'];
102                $dto->session = $raw['SESSION'];
103                $dto->ua = $raw['UA'];
104                $dto->method = $raw['METHOD'];
105                $dto->path = $p;
106                $dto->query = $q;
107                $dto->fragment = $f;
108                $dto->referer = $raw['REFERER'];
109                $dto->runningTime = $raw['RUNNING_TIME'];
110
111                $accessLogs[] = $dto;
112            }
113        }
114
115        if (count($accessLogs)) {
116            $this->logger->info('アクセスログ件数: {0}', count($accessLogs));
117            $database = $this->databaseConnection->open();
118            $database->transaction(function ($context) use ($accessLogs) {
119                $dao = new AccessLogsEntityDao($context);
120                foreach ($accessLogs as $accessLog) {
121                    $dao->insertAccessLog($accessLog);
122                }
123                return true;
124            });
125        } else {
126            $this->logger->info('アクセスログなし');
127        }
128    }
129
130    #endregion
131}