Files
wh-service/app/Service/AliLogsSignService.php
ykxiao 7423491d9c
Some checks failed
Build Docker / build (push) Has been cancelled
仓库金融单据服务
2025-07-08 15:10:36 +08:00

158 lines
4.6 KiB
PHP

<?php
/**
* Author: ykxiao
* Date: 2025/6/3
* Time: 下午7:13
* Description:
*
* (c) ykxiao <yk_9001@hotmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
declare(strict_types=1);
namespace App\Service;
use Hyperf\Config\Annotation\Value;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\ClientFactory;
use function Hyperf\Coroutine\co;
/**
* Author: ykxiao
* Date: 2025/6/3
* Time: 下午7:18
* Description: 阿里云日志服务.
*
* (c) ykxiao <yk_9001@hotmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
class AliLogsSignService
{
protected const string LOG_SIGNATURE_METHOD = 'hmac-sha1';
protected const string LOG_API_VERSION = '0.6.0';
#[Value('alibaba.accessKeyId')]
protected string $accessKeyId;
#[Value('alibaba.accessKeySecret')]
protected string $accessKeySecret;
#[Value('alibaba.logs')]
protected array $logs;
#[Inject]
protected ClientFactory $clientFactory;
/**
* 签名及请求头拼接.
* @param mixed $method
* @param mixed $uri
* @param mixed $params
* @param mixed $body
* @param mixed $logProject
* @param mixed $logEndpoint
*/
public function buildHeaders(
string $method,
string $uri,
array $params,
string $body,
string|object $logProject,
string $logEndpoint
): array
{
$headers = [
'x-log-signaturemethod' => self::LOG_SIGNATURE_METHOD,
'x-log-apiversion' => self::LOG_API_VERSION,
'Host' => sprintf('%s.%s', $logProject, $logEndpoint),
'Content-Type' => 'application/json',
];
$contentLength = 0;
$contentMd5 = '';
if (!empty($body) && strlen($body) > 0) {
$contentLength = strlen($body);
$contentMd5 = strtoupper(md5($body));
$headers['Content-MD5'] = $contentMd5;
}
// date
setlocale(LC_TIME, 'en_US');
$date = gmdate('D, d M Y H:i:s \G\M\T', time());
$headers['Date'] = $date;
$headers['Content-Length'] = (string)$contentLength;
$contentType = $headers['Content-Type'];
$message = $method . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n";
// header
$filterHeaders = [];
foreach ($headers as $key => $val) {
if (str_starts_with($key, 'x-log-') || str_starts_with($key, 'x-acs-')) {
$filterHeaders[$key] = $val;
}
}
ksort($filterHeaders);
foreach ($filterHeaders as $key => $val) {
$message .= $key . ':' . $val . "\n";
}
// uri and params
$message .= $uri;
if (sizeof($params) > 0) {
$message .= '?';
}
ksort($params);
$sep = '';
foreach ($params as $key => $val) {
$message .= $sep . $key . '=' . $val;
$sep = '&';
}
// signature & authorization
$signature = $this->generateSignature($message);
$auth = 'LOG ' . $this->accessKeyId . ':' . $signature;
$headers['Authorization'] = $auth;
return $headers;
}
/**
* 实现调用PutWebTracking接口将多条日志合并进行采集.
*/
public function putWebTracking(array $record): void
{
$logEndpoint = $this->logs['log_endpoint'];
$logProject = $this->logs['log_project'];
$logStores = $this->logs['log_store'];
$params = [];
$body = [
'__topic__' => 'mes api logs',
'__source__' => 'admin api',
'__logs__' => [
['Logs' => $record['formatted']],
],
'__tags__' => [
'mes' => $record['channel'],
],
];
$body = json_encode($body);
$sign_url = sprintf('/logstores/%s/track', $logStores);
$headers = $this->buildHeaders('POST', $sign_url, $params, $body, $logProject, $logEndpoint);
$options = [
'headers' => $headers,
'body' => $body,
'query' => $params,
];
$url = sprintf('https://%s.%s/logstores/%s/track', $logProject, $logEndpoint, $logStores);
$client = $this->clientFactory->create();
co(function () use ($client, $url, $options) {
$client->request('POST', $url, $options);
});
}
protected function generateSignature(string $message): string
{
return base64_encode(hash_hmac('sha1', $message, $this->accessKeySecret, true));
}
}