作者 周海龙

合并分支 'zhl' 到 'master'

监控脚本



查看合并请求 !1866
<?php
/**
* Created by PhpStorm.
* User: zhl
* Date: 2025/4/15
* Time: 10:25
*/
namespace App\Console\Commands\Monitor;
use App\Models\Domain\DomainInfo;
use App\Models\Product\Keyword;
use App\Models\Project\OnlineCheck;
use App\Models\Project\Project;
use App\Repositories\ToolRepository;
use App\Services\DingService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
/**
* Class Supervisory
* @package App\Console\Commands\Monitor
*/
class Supervisory extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'monitor_supervisory';
/**
* The console command description.
*
* @var string
*/
protected $description = '监控脚本';
/**
* Supervisory constructor.
*/
public function __construct()
{
parent::__construct();
}
/**
* @return bool
*/
public function handle()
{
list($robots_ids, $close_ids) = $this->getRobotsProject();
$spot_projects = $this->getSpotCheck();
#TODO robots、 TDK、 top-search、 top-blog
list($error_num, $error, $error_url, $page_404, $tdk_error) = $this->spotCheckPage($spot_projects);
$this->sendMessage($robots_ids, $close_ids, $error_num, $error, $error_url, $page_404, $tdk_error, $spot_projects);
return true;
}
/**
* 抽查数据
* @param $projects
* @return array
*/
public function spotCheckPage($projects)
{
$error_num = 0;
$error = [];
$error_url = [];
$page_404 = [];
$tdk_error = [];
$tdk = [];
foreach ($projects as $project) {
$this->output('抽查项目:' . $project['project_id'] . ', 域名:' . $project['domain']);
$host = 'https://' . $project['domain'] . '/';
// AI blog页面
$blog_url = $host . 'top-blog/';
list($blog_code, $blog_html) = app(ToolRepository::class)->curlRequest($blog_url, [], $method = 'GET', [], 10);
if ($blog_code != 200) {
$error_num++;
array_push($error_url, $blog_url);
} else {
$tdk = $this->analysisHtml($blog_html);
if (FALSE == is_array($tdk)) {
$error_num++;
array_push($error, $blog_url);
} else if (empty($tdk['title'])) {
array_push($tdk_error, $blog_url);
} else if (FALSE !== strpos('404', $tdk['title'])){
array_push($page_404, $blog_url);
}
}
// top search页面
$search_url = $host . 'top-search/';
list($search_code, $search_html) = app(ToolRepository::class)->curlRequest($search_url, [], $method = 'GET', [], 10);
if ($search_code != 200) {
$error_num++;
array_push($error_url, $search_url);
} else {
$tdk = $this->analysisHtml($search_html);
if (FALSE == is_array($tdk)) {
$error_num++;
array_push($error, $search_url);
} else if (empty($tdk['title'])) {
array_push($tdk_error, $search_url);
} else if (FALSE !== strpos('404', $tdk['title'])){
array_push($page_404, $search_url);
}
}
// 关键词聚合页
foreach ($project['keyword'] as $item) {
$keyword_url = $host . $item['route'] . '/';
$this->output('抽查url:' . $keyword_url);
list($keyword_code, $keyword_html) = app(ToolRepository::class)->curlRequest($keyword_url, [], $method = 'GET', [], 10);
if ($keyword_code != 200) {
// 请求失败
$error_num++;
array_push($error_url, $keyword_url);
} else {
$tdk = $this->analysisHtml($keyword_html);
if (FALSE == is_array($tdk)) {
// 解析HTML失败
$error_num++;
array_push($error, $keyword_url);
} else if (empty($tdk['title'])) {
array_push($tdk_error, $keyword_url);
} else {
if (FALSE !== strpos('404', $tdk['title'])) {
// 404页面
array_push($page_404, $keyword_url);
} else {
// TDK验证
$tdk = array_filter(array_unique($tdk));
if (count($tdk) < 3)
array_push($tdk_error, $keyword_url);
}
}
}
}
}
return [$error_num, $error, $error_url, $page_404, $tdk_error];
}
/**
* 获取robots信息
* @return array
*/
public function getRobotsProject()
{
$this->output('统计robots start');
$ids = Project::where(['robots' => 1])->pluck('id')->toArray();
file_put_contents(storage_path('data/robots/' . date('Ymd'). '.json'), json_encode($ids, 256));
if (FALSE == is_file(storage_path('data/robots/' . date('Ymd', strtotime('-1 day')). '.json')))
return [$ids, []];
$string = file_get_contents(storage_path('data/robots/' . date('Ymd', strtotime('-1 day')). '.json'));
$yesterday_robots_ids = json_decode($string, true) ?: [];
$close_ids = [];
foreach ($yesterday_robots_ids as $id) {
if (FALSE == in_array($id, $ids)) {
array_push($close_ids, $id);
}
}
return [$ids, $close_ids];
}
/**
* 随机获取抽查项目
* @return array|int|string
*/
public function getRandProject()
{
$this->output('随机获取项目抽查');
$ids = Project::leftJoin('gl_project_deploy_optimize as b', 'gl_project.id', '=', 'b.project_id')
->leftJoin('gl_project_online_check as c', 'gl_project.id', '=', 'c.project_id')
->leftJoin('gl_domain_info as d', 'gl_project.id', '=', 'd.project_id')
->where('gl_project.type', Project::TYPE_TWO)
->where('gl_project.extend_type', 0) // 是否续费是由extend_type字段控制
->where('gl_project.delete_status', Project::IS_DEL_FALSE)
->where(function ($subQuery) {
$subQuery->orwhere('c.qa_status', OnlineCheck::STATUS_ONLINE_TRUE)->orwhere('gl_project.is_upgrade', Project::IS_UPGRADE_TRUE);
})
->pluck('gl_project.id')
->toArray();
$project_ids = array_rand($ids, 10);
return $project_ids;
}
/**
* 获取抽查项目数据
* @return mixed
*/
public function getSpotCheck()
{
$project_ids = $this->getRandProject();
$projects = DomainInfo::whereIn('project_id', $project_ids)->get(['project_id', 'domain'])->toArray();
foreach ($projects as &$project) {
ProjectServer::useProject($project['project_id']);
$keyword = Keyword::where(['project_id' => $project['project_id'], 'status' => Keyword::STATUS_ACTIVE])->inRandomOrder()->take(10)->get(['id', 'title', 'seo_title', 'seo_keywords', 'seo_description', 'route']);
DB::disconnect('custom_mysql');
if ($keyword->isEmpty()) {
$keyword = [];
} else {
$keyword = $keyword->toArray();
}
$project['keyword'] = $keyword;
}
return $projects;
}
/**
* 获取页面TDK 分析请求数据
* @param $html
* @return array|string
*/
public function analysisHtml($html)
{
$result = [];
if (empty($html))
return $result;
try {
$dom = new \DOMDocument();
@$dom->loadHTML($html);
$title = $dom->getElementsByTagName('title');
$metas = $dom->getElementsByTagName('meta');
$result['title'] = $title->length > 0 ? trim($title->item(0)->nodeValue) : '';
foreach ($metas as $meta) {
$name = strtolower($meta->getAttribute('name'));
$content = $meta->getAttribute('content');
if ($name === 'description') {
$result['description'] = trim($content);
} elseif ($name === 'keywords') {
$result['keywords'] = trim($content);
}
}
// 解析页面, 使用完成, 手动释放内存变量
unset($title);
unset($metas);
unset($dom);
return $result;
} catch (\Exception $e) {
return '解析HTML失败:' . $e->getMessage();
}
}
public function sendMessage($robots_ids, $close_ids, $error_num, $error, $error_url, $page_404, $tdk_error, $spot_projects)
{
$tmp = compact('robots_ids', 'close_ids', 'error_num', 'error', 'error_url', 'page_404', 'tdk_error', 'spot_projects');
file_put_contents(storage_path('data/robots/' . date('Ymd'). 'log.json'), json_encode($tmp, 256));
unset($tmp);
$domain = array_column($spot_projects, 'domain');
$domain = array_unique(array_filter($domain));
$message[] = '开启robots项目数:' . count($robots_ids);
$message[] = '关闭robots项目:' . ($close_ids ? implode(',', $close_ids) : '无');
$message[] = '抽查项目数量: ' . count($domain);
$message[] = 'top-blog: ' . count($domain);
$message[] = 'top-search: ' . count($domain);
$message[] = '抽查错误次数:' . $error_num;
$message[] = '抽查项目域名: ' . implode(' 、 ', $domain);
$message[] = '请求失败链接: ' . implode(' 、 ', $error_url);
$message[] = '页面失败链接: ' . implode(' 、 ', $error);
$message[] = '404页面链接: ' . implode(' 、 ', $page_404);
$message[] = 'TDK错误链接: ' . implode(' 、 ', $tdk_error);
$msg = implode(PHP_EOL, $message);
$link = 'https://oapi.dingtalk.com/robot/send?access_token=3927b42d072972fcf572e7b01728bf3e1390e08094d6f77c5f28bfd85b19f09f';
$dingService = new DingService();
$body = [
'keyword' => '项目数据推送',
'msg' => $msg,
'isAtAll' => false, // 是否@所有人
];
$dingService->handle($body, $link);
}
public function output($message)
{
echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
}
}
\ No newline at end of file
... ...
... ... @@ -23,14 +23,14 @@ class DingService
/**
* @remark :钉钉发送错误信息
* @name :handle
* @author :lyh
* @method :post
* @time :2025/3/19 18:03
* 钉钉发送错误信息
* @param array $body
* @param string $link
* @return int
*/
public function handle(array $body)
public function handle(array $body, $link = '')
{
$link = $link ?: self::LINK;
$msgKey = mb_substr($body['msg'], 50);
if (!$this->getData(RedisKey::DING_MSG . $msgKey)) {
$arr = [
... ... @@ -44,7 +44,7 @@ class DingService
'isAtAll' => $body['isAtAll'],
]
];
$re = json_decode(HttpUtils::post(self::LINK, $arr), true);
$re = json_decode(HttpUtils::post($link, $arr), true);
$this->setData(RedisKey::DING_MSG . $msgKey, true, 60);
return $re['errcode'] ?? 0;
}
... ...