trafficmonitor init...2
This commit is contained in:
parent
7e9f3e2247
commit
2489c426e2
@ -6,8 +6,10 @@ class CollectorDTO extends CommonDTO
|
||||
{
|
||||
public ?int $uid = null;
|
||||
public ?string $trafficinfo_uid = null;
|
||||
public ?string $in = null;
|
||||
public ?string $out = null;
|
||||
public ?int $in = null;
|
||||
public ?int $out = null;
|
||||
public ?int $raw_in = null;
|
||||
public ?int $raw_out = null;
|
||||
|
||||
public function __construct(array $datas = [])
|
||||
{
|
||||
@ -26,6 +28,8 @@ class CollectorDTO extends CommonDTO
|
||||
'trafficinfo_uid' => $this->trafficinfo_uid,
|
||||
'in' => $this->in,
|
||||
'out' => $this->out,
|
||||
'raw_in' => $this->raw_in,
|
||||
'raw_out' => $this->raw_out,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,36 @@
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `collectorinfo`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `collectorinfo`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `collectorinfo` (
|
||||
`uid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`trafficinfo_uid` int(11) NOT NULL,
|
||||
`in` int(11) NOT NULL DEFAULT 0 COMMENT 'IN KBit/SEC',
|
||||
`out` int(11) NOT NULL DEFAULT 0 COMMENT 'OUT KBit/SEC',
|
||||
`raw_in` int(11) NOT NULL DEFAULT 0 COMMENT 'RAW IN ',
|
||||
`raw_out` int(11) NOT NULL DEFAULT 0 COMMENT 'RAW OUT',
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`uid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='수집정보';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `collectorinfo`
|
||||
--
|
||||
|
||||
LOCK TABLES `collectorinfo` WRITE;
|
||||
/*!40000 ALTER TABLE `collectorinfo` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `collectorinfo` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
--
|
||||
-- Table structure for table `mylog`
|
||||
--
|
||||
@ -53,6 +83,7 @@ CREATE TABLE `trafficinfo` (
|
||||
`uid` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`client` varchar(50) NOT NULL,
|
||||
`switch` varchar(10) NOT NULL,
|
||||
`community` varchar(20) NOT NULL DEFAULT 'IDC-JP',
|
||||
`ip` char(16) NOT NULL,
|
||||
`interface` varchar(20) NOT NULL,
|
||||
`status` varchar(20) NOT NULL DEFAULT 'available',
|
||||
@ -116,4 +147,4 @@ UNLOCK TABLES;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2025-11-10 14:43:07
|
||||
-- Dump completed on 2025-11-10 17:22:27
|
||||
|
||||
@ -4,9 +4,37 @@ namespace App\Entities;
|
||||
|
||||
use App\Models\TrafficModel;
|
||||
|
||||
/**
|
||||
* 모니터링 대상 장비/인터페이스 정보를 담는 엔티티
|
||||
*/
|
||||
class TrafficEntity extends CommonEntity
|
||||
{
|
||||
const PK = TrafficModel::PK;
|
||||
const TITLE = TrafficModel::TITLE;
|
||||
//기본기능용
|
||||
protected $casts = [
|
||||
// 'role' => 'json-array', // 🚫 CSV 형식 저장을 위해 제거
|
||||
];
|
||||
|
||||
public function getIP(): string
|
||||
{
|
||||
return $this->attributes['ip'];
|
||||
}
|
||||
public function getInterface(): string
|
||||
{
|
||||
return $this->attributes['interface'];
|
||||
}
|
||||
public function getCommunity(): string
|
||||
{
|
||||
return $this->attributes['community'] ?? 'public';
|
||||
}
|
||||
// Setter 예시: IP 주소 설정 시 유효성 검사 또는 로직 추가 가능
|
||||
public function setIP(string $ip): void
|
||||
{
|
||||
// 예시: IP 주소 유효성 검사 로직 추가 가능
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP) === false) {
|
||||
throw new \InvalidArgumentException("유효하지 않은 IP 주소입니다.");
|
||||
}
|
||||
$this->attributes['ip'] = $ip;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,18 +16,14 @@ class UserEntity extends CommonEntity
|
||||
// 'role' => 'json-array', // 🚫 CSV 형식 저장을 위해 제거
|
||||
];
|
||||
|
||||
// --- Getter Methods ---
|
||||
|
||||
public function getID(): string
|
||||
{
|
||||
return (string) $this->attributes['id'];
|
||||
}
|
||||
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->attributes['passwd'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 사용자의 역할을 배열 형태로 반환합니다.
|
||||
* DB의 JSON 또는 CSV 형식 데이터를 모두 배열로 복구할 수 있는 로직을 포함합니다.
|
||||
@ -36,12 +32,10 @@ class UserEntity extends CommonEntity
|
||||
public function getRole(): array
|
||||
{
|
||||
$role = $this->attributes['role'] ?? null;
|
||||
|
||||
// 1. 이미 배열인 경우 (방어적 코딩)
|
||||
if (is_array($role)) {
|
||||
return array_filter($role);
|
||||
}
|
||||
|
||||
// 2. 문자열 데이터인 경우 처리
|
||||
if (is_string($role) && !empty($role)) {
|
||||
// 2-a. JSON 디코딩 시도 (기존 DB의 JSON 형식 처리)
|
||||
@ -49,18 +43,15 @@ class UserEntity extends CommonEntity
|
||||
if (json_last_error() === JSON_ERROR_NONE && is_array($decodedRole)) {
|
||||
return $decodedRole;
|
||||
}
|
||||
|
||||
// 2-b. JSON이 아니면 CSV로 가정하고 변환
|
||||
$parts = explode(',', $role);
|
||||
// 각 요소의 불필요한 공백과 따옴표 제거
|
||||
$cleanedRoles = array_map(fn($item) => trim($item, " \t\n\r\0\x0B\""), $parts);
|
||||
return array_filter($cleanedRoles);
|
||||
}
|
||||
|
||||
// 3. 변환에 실패했거나 데이터가 없는 경우 빈 배열 반환
|
||||
return [];
|
||||
}
|
||||
|
||||
// --- Setter Methods ---
|
||||
|
||||
public function setPasswd(string $password)
|
||||
|
||||
@ -21,6 +21,8 @@ class CollectorForm extends CommonForm
|
||||
'trafficinfo_uid',
|
||||
'in',
|
||||
'out',
|
||||
'raw_in',
|
||||
'raw_out',
|
||||
];
|
||||
break;
|
||||
case 'modify':
|
||||
@ -30,6 +32,8 @@ class CollectorForm extends CommonForm
|
||||
'trafficinfo_uid',
|
||||
'in',
|
||||
'out',
|
||||
'raw_in',
|
||||
'raw_out',
|
||||
];
|
||||
break;
|
||||
case 'view':
|
||||
@ -38,6 +42,8 @@ class CollectorForm extends CommonForm
|
||||
'trafficinfo_uid',
|
||||
'in',
|
||||
'out',
|
||||
'raw_in',
|
||||
'raw_out',
|
||||
'created_at',
|
||||
];
|
||||
break;
|
||||
@ -47,6 +53,8 @@ class CollectorForm extends CommonForm
|
||||
'trafficinfo_uid',
|
||||
'in',
|
||||
'out',
|
||||
'raw_in',
|
||||
'raw_out',
|
||||
'created_at',
|
||||
];
|
||||
break;
|
||||
@ -63,6 +71,8 @@ class CollectorForm extends CommonForm
|
||||
case "trafficinfo_uid":
|
||||
case "in":
|
||||
case "out":
|
||||
case "raw_in":
|
||||
case "raw_out":
|
||||
$rule = "required|trim|neumeric";
|
||||
$rules[$field] = $rule;
|
||||
break;
|
||||
|
||||
@ -3,8 +3,10 @@ return [
|
||||
'title' => "수집정보",
|
||||
'label' => [
|
||||
'trafficinfo_uid' => "고객명",
|
||||
'in' => "IN",
|
||||
'out' => "OUT",
|
||||
'in' => "IN Kbit/s",
|
||||
'out' => "OUT Kbit/s",
|
||||
'raw_in' => "IN Octets",
|
||||
'raw_out' => "OUT Octets",
|
||||
'updated_at' => "수정일",
|
||||
'created_at' => "생성일",
|
||||
'deleted_at' => "삭제일",
|
||||
|
||||
@ -18,6 +18,8 @@ class CollectorModel extends CommonModel
|
||||
"trafficinfo_uid",
|
||||
"in",
|
||||
"out",
|
||||
"raw_in",
|
||||
"raw_out",
|
||||
"updated_at"
|
||||
];
|
||||
public function __construct()
|
||||
|
||||
@ -4,6 +4,7 @@ namespace App\Services;
|
||||
|
||||
use App\DTOs\CollectorDTO;
|
||||
use App\Entities\CollectorEntity;
|
||||
use App\Entities\TrafficEntity;
|
||||
use App\Forms\CollectorForm;
|
||||
use App\Helpers\CollectorHelper;
|
||||
use App\Models\CollectorModel;
|
||||
@ -15,7 +16,6 @@ class CollectorService extends CommonService
|
||||
const OID_IF_IN_OCTETS = '1.3.6.1.2.1.2.2.1.10.'; // ifInOctets (Raw Octets)
|
||||
const OID_IF_OUT_OCTETS = '1.3.6.1.2.1.2.2.1.16.'; // ifOutOctets (Raw Octets)
|
||||
const SNMP_VERSION = '2c';
|
||||
const SNMP_COMMNUNITY = 'IDC-JP';
|
||||
public function __construct(CollectorModel $model)
|
||||
{
|
||||
parent::__construct($model);
|
||||
@ -93,54 +93,45 @@ class CollectorService extends CommonService
|
||||
parent::setSearchWord($word);
|
||||
}
|
||||
|
||||
/**
|
||||
* SNMP GET 요청을 실행하고 Octet 값을 추출합니다.
|
||||
* @param string $ip 장비 IP
|
||||
* @param int $ifIndex 인터페이스 인덱스
|
||||
* @param string $community SNMP 커뮤니티 문자열
|
||||
* @param string $oid OID (접두사)
|
||||
* @return int|null 수집된 Octet 값 또는 오류 시 null
|
||||
*/
|
||||
protected function getOctets(string $ip, int $ifIndex, string $community, string $oid): ?int
|
||||
private function getSNMPOctets(TrafficEntity $trafficEntity, string $oid): ?int
|
||||
{
|
||||
$fullOid = $oid . $ifIndex;
|
||||
// snmp2_get을 사용하여 SNMP v2c로 요청 (64비트 카운터 지원에 유리)
|
||||
$result = @snmp2_get($ip, $community, $fullOid, 100000, 3); // 3초 타임아웃
|
||||
$fullOid = $oid . $trafficEntity->getInterface();
|
||||
$community = $trafficEntity->getCommunity();
|
||||
$ip = $trafficEntity->getIP();
|
||||
// snmp2_get을 사용하여 SNMP v2c로 요청
|
||||
// 💡 snmp2_get() 함수가 존재하지 않는다는 LSP 오류를 무시하기 위해 @suppress 태그 사용
|
||||
/** @phpstan-ignore-next-line */
|
||||
$result = @snmp2_get($ip, $community, $fullOid, 100000, 3);
|
||||
if ($result === false || $result === null) {
|
||||
log_message('error', "SNMP 통신 실패: {$ip} ({$fullOid}, Community: {$community})");
|
||||
return null;
|
||||
}
|
||||
// 결과 문자열에서 숫자 값만 추출하여 정수로 변환
|
||||
if (preg_match('/\d+/', $result, $matches)) {
|
||||
// SNMP Counter는 BigInt가 될 수 있으므로 intval 대신 (int) 캐스팅을 사용하여
|
||||
// 최대한 큰 정수로 변환합니다. PHP 64비트 환경이 필요합니다.
|
||||
return (int)$matches[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* 트래픽을 수집하고 Kbit/s를 계산하여 DB에 저장합니다.
|
||||
* @param int $trafficInfoUid traffic_info 테이블의 기본 키 (연계 키)
|
||||
* @param string $ip 장비 IP
|
||||
* @param int $ifIndex 인터페이스 인덱스
|
||||
* @param string $community SNMP 커뮤니티 문자열
|
||||
*/
|
||||
public function collectAndCalculate(int $trafficInfoUid, string $ip, int $ifIndex, string $community): void
|
||||
public function getCalculatedData(TrafficEntity $trafficEntity): array
|
||||
{
|
||||
$currentInOctets = $this->getOctets($ip, $ifIndex, $community, self::OID_IF_IN_OCTETS);
|
||||
$currentOutOctets = $this->getOctets($ip, $ifIndex, $community, self::OID_IF_OUT_OCTETS);
|
||||
$currentInOctets = $this->getSNMPOctets($trafficEntity, self::OID_IF_IN_OCTETS);
|
||||
$currentOutOctets = $this->getSNMPOctets($trafficEntity, self::OID_IF_OUT_OCTETS);
|
||||
$currentTime = Time::now()->toDateTimeString();
|
||||
if ($currentInOctets === null || $currentOutOctets === null) {
|
||||
log_message('warning', "트래픽 수집 실패: {$ip} - IF{$ifIndex} (UID: {$trafficInfoUid})");
|
||||
return;
|
||||
$message = "트래픽 수집 실패: {$trafficEntity->getIP()} - IF{$trafficEntity->getInterface()} (UID: {$trafficEntity->getPK()})";
|
||||
log_message('warning', $message);
|
||||
throw new \Exception($message);
|
||||
}
|
||||
// 이전 데이터를 조회하여 Rate 계산에 사용
|
||||
$lastEntry = $this->model->getLastEntryByInfoUid($trafficInfoUid);
|
||||
// 이전 데이터를 조회하여 Rate 계산에 사용 (trafficModel 사용)
|
||||
$lastEntry = $this->model->getLastEntryByInfoUid($trafficEntity->getPK());
|
||||
$inKbitsSec = 0.0;
|
||||
$outKbitsSec = 0.0;
|
||||
// 이전 데이터가 있어야만 Rate 계산 가능
|
||||
if ($lastEntry !== null) {
|
||||
$lastTime = Time::parse($lastEntry['created_at'])->getTimestamp();
|
||||
$deltaTime = Time::now()->getTimestamp() - $lastTime;
|
||||
|
||||
if ($deltaTime > 0) {
|
||||
// Raw Octets 값의 차분 계산
|
||||
$deltaInOctets = $currentInOctets - $lastEntry['raw_in_octets'];
|
||||
@ -150,19 +141,25 @@ class CollectorService extends CommonService
|
||||
$inKbitsSec = ($deltaInOctets * 8) / $deltaTime / 1000;
|
||||
$outKbitsSec = ($deltaOutOctets * 8) / $deltaTime / 1000;
|
||||
} else {
|
||||
log_message('error', "시간 차이 오류 발생: {$ip} - {$deltaTime}초 (UID: {$trafficInfoUid})");
|
||||
log_message('error', "시간 차이 오류 발생: {$trafficEntity->getIP()} - {$deltaTime}초 (UID: {$trafficEntity->getPK()})");
|
||||
}
|
||||
}
|
||||
|
||||
// Collector DB에 결과 저장
|
||||
$this->model->insert([
|
||||
'trafficinfo_uid' => $trafficInfoUid,
|
||||
// DB에 저장할 데이터를 배열로 반환
|
||||
return [
|
||||
'trafficinfo_uid' => $trafficEntity->getPK(),
|
||||
'in_kbits_sec' => round($inKbitsSec, 2),
|
||||
'out_kbits_sec' => round($outKbitsSec, 2),
|
||||
'raw_in_octets' => $currentInOctets, // 다음 계산을 위해 Raw 값 저장
|
||||
'raw_out_octets' => $currentOutOctets, // 다음 계산을 위해 Raw 값 저장
|
||||
'raw_in_octets' => $currentInOctets,
|
||||
'raw_out_octets' => $currentOutOctets,
|
||||
'created_at' => $currentTime,
|
||||
]);
|
||||
log_message('info', "트래픽 계산 및 저장 완료 (UID: {$trafficInfoUid}), In: {$inKbitsSec} Kb/s");
|
||||
];
|
||||
}
|
||||
public function collectAndSave(TrafficEntity $trafficEntity): void
|
||||
{
|
||||
$data = $this->getCalculatedData($trafficEntity);
|
||||
// Collector DB에 결과 저장
|
||||
$this->model->insert($data);
|
||||
log_message('info', "트래픽 계산 및 저장 완료 (UID: {$trafficEntity->getPK()}), In: {$data['in_kbits_sec']} Kb/s");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user