From 194ac35d304387cfe4cc46eb2d668f2f6c4f4f7c Mon Sep 17 00:00:00 2001 From: "choi.jh" Date: Thu, 13 Nov 2025 09:30:08 +0900 Subject: [PATCH] trafficmonitor init...1 --- app/Services/CollectorService.php | 52 ++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/app/Services/CollectorService.php b/app/Services/CollectorService.php index 71e92ab..4f4774f 100644 --- a/app/Services/CollectorService.php +++ b/app/Services/CollectorService.php @@ -16,6 +16,8 @@ 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'; + // Counter32의 최대값 + 1 (오버플로우 보정을 위해 사용) + const MAX_COUNTER_32BIT = 4294967296; public function __construct(CollectorModel $model) { parent::__construct($model); @@ -98,37 +100,65 @@ class CollectorService extends CommonService { $currentInOctets = $this->getSNMPOctets($trafficEntity, self::OID_IF_IN_OCTETS); $currentOutOctets = $this->getSNMPOctets($trafficEntity, self::OID_IF_OUT_OCTETS); + if ($currentInOctets === null || $currentOutOctets === null) { $message = "트래픽 수집 실패: {$trafficEntity->getIP()} - IF{$trafficEntity->getInterface()} (UID: {$trafficEntity->getPK()})"; log_message('warning', $message); - throw new \Exception($message); + throw new Exception($message); } + // 이전 데이터를 조회하여 Rate 계산에 사용 + // $this->model은 TrafficDataModel의 인스턴스라고 가정 $lastEntity = $this->model->getLastEntity($trafficEntity->getPK()); - $inKbitsSec = 0; - $outKbitsSec = 0; + + $inKbitsSec = 0.0; + $outKbitsSec = 0.0; + // 이전 데이터가 있어야만 Rate 계산 가능 if ($lastEntity !== null) { $lastTime = Time::parse($lastEntity->getCreatedAt())->getTimestamp(); $deltaTime = Time::now()->getTimestamp() - $lastTime; + if ($deltaTime > 0) { - // Raw Octets 값의 차분 계산 - $deltaInOctets = $currentInOctets - $lastEntity->getRawIn(); - $deltaOutOctets = $currentOutOctets - $lastEntity->getRawOut(); + $lastIn = $lastEntity->getRawIn(); + $lastOut = $lastEntity->getRawOut(); + + // 💡 1. 인바운드 Octets 차분 계산 (오버플로우 처리) + if ($currentInOctets < $lastIn) { + // 카운터 롤오버 발생: Delta = (MAX - Last) + Current + $deltaInOctets = (self::MAX_COUNTER_32BIT - $lastIn) + $currentInOctets; + log_message('info', "Inbound Rollover Detected for UID: {$trafficEntity->getPK()}. Delta: {$deltaInOctets}"); + } else { + // 정상적인 차분 + $deltaInOctets = $currentInOctets - $lastIn; + } + + // 💡 2. 아웃바운드 Octets 차분 계산 (오버플로우 처리) + if ($currentOutOctets < $lastOut) { + // 카운터 롤오버 발생 + $deltaOutOctets = (self::MAX_COUNTER_32BIT - $lastOut) + $currentOutOctets; + log_message('info', "Outbound Rollover Detected for UID: {$trafficEntity->getPK()}. Delta: {$deltaOutOctets}"); + } else { + // 정상적인 차분 + $deltaOutOctets = $currentOutOctets - $lastOut; + } + // Kbit/s 계산: (Delta_Octets * 8 bits) / Delta_Time_Seconds / 1000 (-> Kbit/s) - $inKbitsSec = ($deltaInOctets * 8) / $deltaTime / 1000; - $outKbitsSec = ($deltaOutOctets * 8) / $deltaTime / 1000; + // 실수(float) 연산으로 정확도를 높입니다. + $inKbitsSec = ($deltaInOctets * 8.0) / $deltaTime / 1000.0; + $outKbitsSec = ($deltaOutOctets * 8.0) / $deltaTime / 1000.0; } else { log_message('error', "시간 차이 오류 발생: {$trafficEntity->getIP()} - {$deltaTime}초 (UID: {$trafficEntity->getPK()})"); } } + // DB에 저장할 데이터를 배열로 반환 return [ + // 💡 정수 캐스팅 대신 반올림을 사용하여 정밀도 유지 및 데이터 형식 일치 'trafficinfo_uid' => (int)$trafficEntity->getPK(), - 'in' => (int)$inKbitsSec, - 'out' => (int)$outKbitsSec, + 'in' => round($inKbitsSec, 2), // 소수점 2자리까지 반올림 + 'out' => round($outKbitsSec, 2), // 소수점 2자리까지 반올림 'raw_in' => (int)$currentInOctets, 'raw_out' => (int)$currentOutOctets, ]; - } }