RRDtool - 윈디하나의 솔라나라
|
시간 기반의 데이터를 저장하는 산업 표준 오픈 소스 로깅/그래프 도구이다.라고 홈페이지에 나와있다. TSDB의 대표격이다. 쉽게 말하자면,
수신/발신 데이터의 양와 같이 시간의 흐름에 따라 쌓이는 데이터를 효율적으로 관리하고 표시하기 위한 툴이라는 의미다.
windy@wl ~ $ sudo pkg install pkg://solaris/image/rrdtool1.6 버전이 설치된다.
최신 버전이 필요하다면 Releases · oetiker/rrdtool-1.x · GitHub에서 최신 소스를 받아 빌드하자. 구 버전은 RRDtool Download Area에서 소스를 받을 수 있다. 위에서 설명한 패키지 설치 이후 진행해야 한다. 필요한 라이브러리 목록은 윈디하나의 솔라나라: rrdtool 1.4 (작성중)를 참고하자.
windy@wl ~/src $ wget https://github.com/oetiker/rrdtool-1.x/releases/download/v1.9.0/rrdtool-1.9.0.tar.gz windy@wl ~/src $ tar xvfz rrdtool-1.9.0.tar.gz windy@wl ~/src $ cd rrdtool-1.9.0 windy@wl ~/src/rrdtool-1.9.0 $ LD_LIBRARY_PATH="" CFLAGS="" LDFLAGS="-L/usr/lib -R/usr/lib" ./configure --disable-python --disable-perl 1) windy@wl ~/src/rrdtool-1.9.0 $ vi src/rrd_list.c 2) #include <limits.h> windy@wl ~/src/rrdtool-1.9.0 $ LD_LIBRARY_PATH="" make windy@wl ~/src/rrdtool-1.9.0 $ sudo make install1) 32비트로 빌드 한다. 솔라리스 11.4에 있는 펄 및 파이썬 라이브러리가 32비트이기 때문에 64비트로 빌드하면 오류가 발생한다. 추후 변경될 수 있다.
PATH_MAX
상수가 limits.h
에 있다. limits.h
를 추가하자. 리눅스에서는 추가할 필요 없다.make install
을 실행하면 /opt/rrdtool-1.9.0
에 아래와 같은 파일이 설치된다.
windy@wl ~ $ ls -al /opt/rrdtool-1.9.0/bin -rwxr-xr-x 1 root root 121476 8월 10 11:24 rrdcached -rwxr-xr-x 1 root root 41504 8월 10 11:24 rrdcgi lrwxrwxrwx 1 root root 9 8월 10 11:24 rrdcreate -> rrdupdate lrwxrwxrwx 1 root root 9 8월 10 11:24 rrdinfo -> rrdupdate -rwxr-xr-x 1 root root 34344 8월 10 11:24 rrdtool -rwxr-xr-x 1 root root 309836 8월 10 11:24 rrdupdate
.rrd
파일을 캐시해 처리속도를 높일 수 있는 유틸. RRDTool 1.8 미만 버전에서는 메모리 누수가 있으므로 1.8 이상의 최신버전을 사용하자.root@wll ~ # yum install rrdtoolRHEL 6에서는 1.3 버전이 설치된다. 1.3에는 rrdcached(1) 가 없기 때문에 캐시를 사용한 예제는 사용할 수 없다. 하지만 이 문서를 주된 내용인 그래프를 그리는 부분을 사용하는데에는 전혀 지장 없다.
Windows 기능에서
Subsystem for UNIX based Applications를 설치하고, Utilities and SDK for Subsystem for UNIX-based Applications in Microsoft Windows 7 and Windows Server 2008 R2를 설치하면 사용하기 쉬워질 것이다.
런 큐에 대기하고 있는 작업 개수의 평균을 의미하는 값으로 시스템에 걸리는 부하를 대표하는 값이다.
windy@wl ~ $ LANG=C uptime
00:00am up 1 day(s), 00:00, 1 user, load average: 0.15, 0.18, 0.18
windy@wl ~ $ snmpwalk -v 2c -c public localhost .1.3.6.1.4.1.2021.10 UCD-SNMP-MIB::laIndex.1 = INTEGER: 1 UCD-SNMP-MIB::laIndex.2 = INTEGER: 2 UCD-SNMP-MIB::laIndex.3 = INTEGER: 3 UCD-SNMP-MIB::laNames.1 = STRING: Load-1 UCD-SNMP-MIB::laNames.2 = STRING: Load-5 UCD-SNMP-MIB::laNames.3 = STRING: Load-15 UCD-SNMP-MIB::laLoad.1 = STRING: 0.23 UCD-SNMP-MIB::laLoad.2 = STRING: 0.26 UCD-SNMP-MIB::laLoad.3 = STRING: 0.23 UCD-SNMP-MIB::laConfig.1 = STRING: 12.00 UCD-SNMP-MIB::laConfig.2 = STRING: 12.00 UCD-SNMP-MIB::laConfig.3 = STRING: 12.00 UCD-SNMP-MIB::laLoadInt.1 = INTEGER: 23 UCD-SNMP-MIB::laLoadInt.2 = INTEGER: 25 UCD-SNMP-MIB::laLoadInt.3 = INTEGER: 23 UCD-SNMP-MIB::laLoadFloat.1 = Opaque: Float: 0.230469 UCD-SNMP-MIB::laLoadFloat.2 = Opaque: Float: 0.257812 UCD-SNMP-MIB::laLoadFloat.3 = Opaque: Float: 0.230469 UCD-SNMP-MIB::laErrorFlag.1 = INTEGER: noError(0) UCD-SNMP-MIB::laErrorFlag.2 = INTEGER: noError(0) UCD-SNMP-MIB::laErrorFlag.3 = INTEGER: noError(0) UCD-SNMP-MIB::laErrMessage.1 = STRING: UCD-SNMP-MIB::laErrMessage.2 = STRING: UCD-SNMP-MIB::laErrMessage.3 = STRING: windy@wl ~ $ snmpwalk -v 2c -c public localhost laLoadFloat.1 UCD-SNMP-MIB::laLoadFloat.1 = Opaque: Float: 0.230469SNMP서버를 설정해야 하는 번거로움이 있어 이 예시에서는 이 방법을 사용하지 않는다.
1분 간격으로 수집하고 그래프를 출력하도록 하자.
우선 데이터를 저장할 .rrd
파일을 생성해야 한다. .rrd
파일은 rrdtool create
명령을 사용해 생성하며, 생성시 데이터 종류와 저장 방법, 업데이트 주기등을 지정해야 한다. 자세한 사항은 rrdcreate(1)을 참조하자.
시스템 부하의 경우 1분, 5분, 15분의 부동소수점 데이터가 된다. 따라서 아래와 같이 생성할 수 있다.
windy@wl ~ $ rrdtool create load.rrd \ --step 60 \ DS:1min:GAUGE:600:0:U \ DS:5min:GAUGE:600:0:U \ DS:15min:GAUGE:600:0:U \ RRA:AVERAGE:0.5:1:1440 \ RRA:AVERAGE:0.5:5:1440 \ RRA:AVERAGE:0.5:30:800 \ RRA:AVERAGE:0.5:120:800 \ RRA:AVERAGE:0.5:1440:800 \ RRA:MAX:0.5:60:2400
load.rrd
: rrd 파일의 이름. 임의로 정해줄 수 있다.--step
: 데이터 입력 주기. 단위는 초. 위에서는 1분으로 설정했다.DS
: DataSource. 데이터 소스를 지정한다. DS:ds-name:DST:dst arguments
형식으로 지정해 준다. dst arguments는 DST 에 따라 두가지 문법을 가진다.
DS:ds-name:{GAUGE | COUNTER | DERIVE | DCOUNTER | DDERIVE | ABSOLUTE}:heartbeat:min:max
DS:ds-name:COMPUTE:rpn-expression
ds-name
: 데이터 소스 이름. 임의로 지정한다.DST
: Data Source Type. 데이터 소스의 형식. 아래와 같이 있다.
GAUGE
: 입력된 값을 그대로 사용. 현재 1분 동안 솔라나라의 방문자수와 같은 의미이다.
COUNTER
: 데이터주기에 의해 입력된 값과 이전 값을 비교해 초당 '비율'을 저장. 양수값만 취한다. [(현재값 - 이전값) / (현재시간(초) - 이전시간(초))] 로 계산된다. 솔라나라의 누적 방문자수를 처리하는데 유용하게 사용한다.
DCOUNTER
: COUNTER와 비슷하나 부동 소숫점을 사용. RRDtool 1.5 부터 지원.DERIVE
: 데이터주기에 의해 입력된 값과 이전 값을 비교해 초당 '비율'을 저장. COUNTER와 비슷하지만, 양수값 외에 음수값도 취할 수 있다.DDERIVE
: DERIVE와 비슷하나 부동 소숫점을 사용. RRDtool 1.5 부터 지원.ABSOLUTE
: 입력된 값은 증감값이다.COMPUTE
: RRD의 외부 플러그인에 의해 계산된 값이다.GAUGE
이다.
heartbeat
: 데이터 입력이 --step 인자에 명시된 대로 정시에 입력되면 좋겠지만 현실에서는 그렇지 않을 것이다. 여기에 지정된 값만큼의 오차를 감안한다. 단위는 초이다. 반드시 --step 에 지정된 값 보다 커야 하며, --step 에 지정된 값의 두 배 이상 지정해줘도 좋다. heartbeat 에 정의된 시간까지 기다려도 데이터가 입력되지 않은 경우 해당 시간의 데이터는 UNKNOWN으로 간주하고 MIN, MAX등을 계산해 보여준다.min
: 입력할 값의 최소값. U는 unknown. 이 값보다 작은 값이 입력되면 UNKNOWN으로 처리한다.max
: 입력할 값의 최대값. U는 unknown. 이 값보다 큰 값이 입력되면 UNKNOWN으로 처리한다.rpn-expression
: RPN 표현식. RPN에 대한 설명은 RRDtool - rrdgraph_rpn페이지를 참조한다RRA
: Round Robin Archive
. 저장 방식을 지정한다. RRA:CF:cf arguments
형식이며, 결과적으로 아래와 같은 문법을 가진다.
RRA:AVERAGE|MIN|MAX|LAST:xff:steps:rows
CF
: Consolidation Function. AVERAGE, MIN, MAX, LAST 가 있다.
AVERAGE
: 평균값을 저장MIN
: 최소값을 저장MAX
: 최대값을 저장LAST
: 마지막값을 저장xff
: xfiles factor. 알 수 없는 데이터가 들어오는 경우 얼마나 오래동안 KNOWN 데이터로 간주할 것인지 지정. 0~1 사이의 값이며, 보통 0.5로 설정한다. 예를 들어 xff를 0.5로 설정한 경우 1, unknown, unknown, 1
의 50%가 데이터가 들어온 경우에 대한 평균은 1이다. 1, unknown, unknown, unknown
와 같이 75%가 unknown인 경우 결과는 unknown 이 된다.steps
: 평균값/최소값/최대값을 계산할때 사용되는 값의 개수. 이 값이 1이면 결과적으로 LAST와 같아진다.rows
: RRA에 저장될 값의 개수. 이후에는 값을 제거한다. 1년 단위의 데이터를 저장하려면 이 값이 충분히 커야 한다. 하단의 참고데이터를 보자.RRA:HWPREDICT:rows:alpha:beta:seasonal period[:rra-num]자세한건 RRDtool create Example 을 읽어보자. 아래에 생성 예제가 있다.
RRA:MHWPREDICT:rows:alpha:beta:seasonal period[:rra-num]
RRA:SEASONAL:seasonal period:gamma:rra-num[:smoothing-window=fraction]
RRA:DEVSEASONAL:seasonal period:gamma:rra-num[:smoothing-window=fraction]
RRA:DEVPREDICT:rows:rra-num
RRA:FAILURES:rows:threshold:window length:rra-num
windy@wl ~ $ rrdtool create monitor.rrd --step 300 \ DS:ifOutOctets:COUNTER:1800:0:U \ RRA:AVERAGE:0.5:1:2016 \ RRA:HWPREDICT:1440:0.1:0.0035:288:3 \ RRA:SEASONAL:288:0.1:2 \ RRA:DEVPREDICT:1440:5 \ RRA:DEVSEASONAL:288:0.1:2 \ RRA:FAILURES:288:7:9:5
RRA에는 HWPREDICT 만 정의해도 나머지 값(SEASONAL, DEVPREDICT, DEVSESONAL, FAILURES)이 같이 정의된다. HWPREDICT 와 MHWPREDICT 는 계산된 오차범위를 합산 하느냐, 곱하느냐의 차이다. 잘 모르겠으면 두가지 다 해보고 적당한 방식을 찾으면 된다.
이외에도 RRDTool은 파일을 Ceph클러스터에 저장할 수 있다. Ceph 가 설정되고 RRDTool 과 같이 빌드되었다면, load.rrd
대신 ceph//load.rrd
과 같이 명령 옵션을 주면 된다. 자세한 사항은 RRDTool - rrdrados를 읽어보자.
DS:ds1:COUNTER:600:0:U으로 생성한 경우, step 이 60인 경우 아래와 같이 계산된다.
시간 입력값 계산된값 .rrd 파일 저장 값 0 600 600 10 60 900 300 5 120 1500 600 10 180 300 약 232 약 232 / 60 240 900 600 10 ...입력값(rrdupdate 커맨드로 입력해주는 값)이 줄어드는 경우는 보통 시스템이 리부트 되었거나 오버플로가 일어난 경우다. 하지만 위의 경우 32비트 오버플로로 간주해 (232 - 1500 + 300)로 계산하고, 파일에는 이를 초당 비율로 계산한 값을 저장한다. 따라서 이 값을 토대로 그래프를 그리면 비 정상적인 모양이 나오게 된다.
DS:ds1:DERIVE:600:0:U아래와 같이 계산된다.
시간 입력값 계산된값 .rrd 파일 저장 값 0 600 600 10 60 900 300 5 120 1500 600 10 180 300 -1200 U 240 900 600 10 ...최소값은 0으로 지정했기 때문에 음수가 들어와 값을 취하지 않게 된다. 이 방법은 값을 하나 버리는 문제가 있지만 (심지어 오버플로가 발생해 줄어든 값이라도 버리게 된다) 카운터 리셋에 의한 문제는 방지할 수 있다.
DS:ds1:COUNTER:600:0:1000으로 가정하면
시간 입력값 계산된값 .rrd 파일 저장 값 0 600 600 10 60 900 300 5 120 1500 600 10 180 300 약 232 U 240 900 600 10 ...
COUNTER
를 사용하였으며, 오버플로에 의해 낮아진 경우가 아니라면 rrdupdate 명령 실행시 입력값을 U로 주어 해결했다. 당장 60동안의 입력값은 문제가 되지만, 텀이 더 긴 그래프에서는 U는 무시되고 평균 값를 계산하기 때문에 문제가 되지 않는다.
시간 입력값 계산된값 .rrd 파일 저장 값 0 600 600 10 60 900 300 5 120 1500 600 10 180 U U U 240 900 900 15 ...DERIVE를 사용한 예와 비교하면 마지막 값이 다르다. 어떤것을 취할지는 각자의 판단에 맞긴다. rrdupdate 구문을 수행하는데 좀 더 계산을 해야 하지만 가능하다면 이 방법을 추천한다.
rrdupdate(1)은 .rrd
파일을 업데이트한다. .rrd
파일을 생성할때 지정했던 주기로 데이터를 업데이트해야 한다. 아래와 같은 형식을 지닌다.
rrdupdate 파일명 시간:데이터1[[:데이터2]...]
시스템 부하의 경우 1분 주기로 하기로 하였으며, 부동소수점을 가진 데이터 3개를 업데이트 해야 한다. 따라서 아래와 같이 명령을 줄 수 있다.
windy@wl ~ $ rrdupdate load.rrd N:1.0:0.8:0.5 1)
1) rrdupdate(1) 대신 rrdtool update
를 사용해도 된다. rrdupdate(1)는 정적 라이브러리를 사용해 빌드 되어있다.
각각의 인자는 아래와 같은 의미를 지닌다.
load.rrd
: 업데이트할 rrd 파일의 이름. rrdtool create
로 생성한 파일이다.N
: 현재시간을 의미한다. 이외에 유닉스 타임스탬프(Unix Timestamp)를 사용할 수 있다.:value
: 값을 지정해 준다. create 시 3개의 값을 지정했기 때문에 (DS가 3개)3개의 값을 업데이트 해야 한다.이외에 --template
옵션을 통해 갱신할 DS를 지정해줄 수 있다.
rrdtool info
명령은 .rrd
파일의 헤더 정보를 보여준다. 자세한 사항은 rrdinfo(1) 을 참조하자.
windy@wl ~ $ rrdtool info load.rrd filename = "load.rrd" rrd_version = "0003" step = 60 last_update = 1279679701 ds[1min].type = "GAUGE" ds[1min].minimal_heartbeat = 600 ds[1min].min = 0.0000000000e+00 ds[1min].max = NaN ds[1min].last_ds = "0.070000" ds[1min].value = 1.1743837000e-01 ds[1min].unknown_sec = 0 ... rra[0].cf = "AVERAGE" rra[0].rows = 1440 rra[0].cur_row = 107 rra[0].pdp_per_row = 1 rra[0].xff = 5.0000000000e-01 ... rra[1].cf = "MAX" rra[1].rows = 2400 rra[1].cur_row = 1001 rra[1].pdp_per_row = 60 rra[1].xff = 5.0000000000e-01
rrdtool fetch
명령은 .rrd
파일에 저장된 데이터를 보여준다. 파일에 저장된 모든 LAST 데이터를 보려면 아래와 같이 한다. 자세한 사항은 rrdfetch(1)을 참조하자.
windy@wl ~ $ rrdtool fetch load.rrd LAST ... 1267434480: 1.1095090793e+00 1.0797545397e+00 8.9975453967e-01 1267434540: 1.0607886517e+00 1.0701577303e+00 9.0984226967e-01 1267434600: 1.0797463910e+00 1.0798731955e+00 9.2974639100e-01 1267434660: 1.0408642967e+00 1.0702160742e+00 9.3000000000e-01 1267434720: -NaN -NaN -NaN
rrdtool last
명령은 마지막으로 업데이트된 날짜를 보여준다. 자세한 사항은 rrdlast(1)을 참조하자.
windy@wl ~ $ rrdtool last load.rrd 1267434668
rrdtool lastupdate
명령은 마지막으로 업데이트된 데이터를 보여준다. 자세한 사항은 rrdlastupdate(1)을 참조하자.
windy@wl ~ $ rrdtool lastupdate load.rrd 1min 5min 15min 1267434660: 1.0408642967e+00 1.0702160742e+00 9.3000000000e-01
windy@wl ~ $ rrdtool fetch localhost.rrd AVERAGE -r 864000 -s 1393599600 -e 1396278000 ds0 ds1 ... 1395360000: 1.5381875000e+03 1.7920729167e+04 1395446400: 1.0164756944e+03 1.8497173611e+04 1395532800: 1.1983329861e+04 1.0146190972e+04 1395619200: 1.1118963194e+05 1.8114218750e+04 1395705600: 1.9604527950e+04 1.1155314485e+05 ...
1395360000는 유닉스 타임스탬프다.
1970년 1월 1일(UTC)기준으로 지난
초를 저장한다. 따라서
1395360000는
2014.03.21 00:00:00
이다. 인터넷에 유닉스 타임스탬프 변환기를 찾으면 시간 변환을 쉽게 할 수 있다.1.5381875000e+03 × 864000 = 132899400 ≒ 126 MiB
-r
값을 1시간이나 5분으로 변경시키면 그에 따라 자동으로 계산되어 값이 나온다. 문서 하단에서 설명할 예측 알고리즘을 사용하면 미래의 예측 데이터도 추출할 수 있다.
rrdtool tune
명령은 .rrd
파일의 구조를 수정할 수 있다. 자세한 사항은 rrdtune(1)을 참조하자.
windy@wl ~ $ rrdtool tune RRDtool 1.7.1 Copyright by Tobias Oetiker <tobi@oetiker.ch> Compiled Feb 00 2019 00:00:00 Usage: rrdtool [options] command command_options * tune - Modify some basic properties of an RRD rrdtool tune filename [--heartbeat|-h ds-name:heartbeat] [--data-source-type|-d ds-name:DST] [--data-source-rename|-r old-name:new-name] [--minimum|-i ds-name:min] [--maximum|-a ds-name:max] [--deltapos|-p scale-value] [--deltaneg|-n scale-value] [--failure-threshold|-f integer] [--window-length|-w integer] [--alpha|-x adaptation-parameter] [--beta|-y adaptation-parameter] [--gamma|-z adaptation-parameter] [--gamma-deviation|-v adaptation-parameter] [--smoothing-window|-s fraction-of-season] [--smoothing-window-deviation|-S fraction-of-season] [--aberrant-reset|-b ds-name] [--step|-t newstep] [--daemon|-D address] [DEL:ds-name] [DS:ds-spec] [DELRRA:index] [RRA:rra-spec] [RRA#index:[+-=]number] RRDtool is distributed under the Terms of the GNU General Public License Version 2. (www.gnu.org/copyleft/gpl.html) For more information read the RRD manpages
rrdtool dump
명령은 .rrd
포맷을 XML으로 변환한다. rrdtool restore
명령은 그 역 변환이다. RRDtool은 컬럼 하나를 임의의 값으로 수정하는 방법을 제공하지 않는데, 이를 통해 변경할 수 있다. 자세한 사항은 rrddump(1), rrdrestore(1)을 참조하자.windy@wl ~ $ rrdtool dump counter.rrd dump <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE rrd SYSTEM "http://oss.oetiker.ch/rrdtool/rrdtool.dtd"> <!-- Round Robin Database Dump --> <rrd> <version>0003</version> <step>60</step> <!-- Seconds --> <lastupdate>1397227383</lastupdate> <!-- 2014-04-11 23:43:03 KST --> <ds> <name> cnt </name> <type> COUNTER </type> <minimal_heartbeat>6000</minimal_heartbeat> <min>0.0000000000e+00</min> <max>NaN</max> <!-- PDP Status --> <last_ds>5745396</last_ds> <value>2.1841500000e+03</value> <unknown_sec> 0 </unknown_sec> </ds> <!-- Round Robin Archives --> <rra> <cf>AVERAGE</cf> <pdp_per_row>1</pdp_per_row> <!-- 60 seconds --> <params> <xff>5.0000000000e-01</xff> </params> <cdp_prep> <ds> <primary_value>7.0959166667e+02</primary_value> <secondary_value>NaN</secondary_value> <value>NaN</value> <unknown_datapoints>0</unknown_datapoints> </ds> </cdp_prep> <database> ... <!-- 2014-04-11 23:26:00 KST / 1397226360 --> <row><v>NaN</v></row> <!-- 2014-04-11 23:27:00 KST / 1397226420 --> <row><v>1.4198816667e+03</v></row> </database> </rra> </rrd>
windy@wl ~ $ rrdtool dump counter.rrd > counter.xml windy@wl ~ $ vi counter.xml ... windy@wl ~ $ rm counter.rrd windy@wl ~ $ rrdtool restore counter.xml counter.rrd
rrdtool resize
명령은 RRA크기를 바꿔 .rrd
파일을 생성한다. 현재 RRA 크기는 rrdinfo(1)을 사용해 알 수 있다. 자세한 사항은 rrdresize(1)을 참조하자.windy@wl ~ $ rrdtool info load.rrd | grep index ds[1min].index = 0 ds[5min].index = 1 ds[15min].index = 2 ds[uptime].index = 3 windy@wl ~ $ rrdtool info load.rrd | grep rows rra[0].rows = 1440 rra[1].rows = 1440 rra[2].rows = 800 rra[3].rows = 800 rra[4].rows = 800 windy@wl ~ $ rrdtool resize load.rrd 1min SHRINK 100 windy@wl ~ $ rrdtool info resize.rrd | grep rows rra[0].rows = 1440 rra[1].rows = 1340 rra[2].rows = 800 rra[3].rows = 800 rra[4].rows = 800
rrdtool 은 연산식을 입력할 때 RPN을 사용한다. 자세한 사항은 rrdgraph_rpn을 참고하자. 사용할 수 있는 연산자 목록을 아래에 정리했다.
UN
, ISINF
: 1개의 데이터를 스택에서 팝한 후, Unknown 및 음/양의무한대인경우 1을, 그렇지 않는 경우 0 을 스택에 푸시해준다.then,else,condition,IF
: 3개의 데이터를 스택에서 팝한 후, condition 이 0 인경우 else 를, 그렇지 않는 경우 then 값을 스택에 푸시한다.MIN
, MAX
: 2개의 데이터를 스택에서 팝 한 후, 최대/최소 값을 스택에 푸시한다. 값중에 NaN 이 있다면 결과는 NaN이다.MINNAN
, MAXNAN
: 2개의 데이터를 스택에서 팝 한 후, 최대/최소 값을 스택에 푸시한다. 값중에 NaN 이 있다면 무시되지만, 두 값이 모두 NaN 이면 결과는 NaN이다.val,lower-limit,upper-limit,LIMIT
: 3개의 데이터를 스택에서 팝한 후, 범위 안에 있으면 val 을, 그렇지 않으면 Unknown 을 스택에 푸시한다.ADDNAN
: NaN 에 안전한 더하기. NaN 은 0으로 간주되어 계산된지만, 둘 다 NaN 인경우 NaN 이다.value,power,POW
: 거듭제곱(valuepower
)을 구한다.SIN
, COS
, LOG
, EXP
, SQRT
: 사인(라디안), 코사인(라디안), 로그(자연로그), 지수(자연로그), 제곱근을 구한다.ATAN
: 아크 탄젠트를 구한다. (라디안)y,x,ATAN2
: 아크 탄젠트를 구한다(라디안)FLOOR
, CEIL
: 내림, 올림을 구한다.DEG2RAD
, RAD2DEG
: DEGrees, RADians 간 변환한다.ABS
: 절대값을 구한다.count,SORT
: 스택에서 지정한 개수만큼 데이터를 꺼내어 정렬한후 다시 스택에 넣는다.count,REV
: 스택에서 지정한 개수만큼 데이터를 꺼내어 순서를 반대로 뒤집은 후 다시 스택에 넣는다.count,AVG
: 스택에서 지정한 개수만큼 데이터를 꺼내어 평균을 구한후 다시 스택에 넣는다.count,SMIN
및 count,SMAX
: 스택에서 지정한 개수만큼 데이터를 꺼내어 최대/최소를 구한후 다시 스택에 넣는다.count,MEDIAN
: 스택에서 지정한 개수만큼 데이터를 꺼내어 중앙값을 구한후 다시 스택에 넣는다. UNKNOWN 값은 무시된다.count,STDEV
: 스택에서 지정한 개수만큼 데이터를 꺼내어 표준편차를 구한후 다시 스택에 넣는다. NAN 값은 무시된다.percent,count,PERCENT
: 스택에서 지정한 개수만큼 데이터를 꺼내어 정렬한 후 지정된 비율번째에 해당하는 값을 구한후 다시 스택에 넣는다.count,TREND
및 count,TRENDNAN
: 평균값을 이용해 지정한 시간 만큼의 슬라이딩 윈도우를 생성한다.PREDICT
, PREDICTSIGMA
, PREDICTPERC
: 평균값/시그마값/백분위수를 사용해 슬라이딩 윈도우를 생성한후 예측된 데이터를 넣는다. 미래의 값을 예측할때 사용한다.CDEF:x=v1,v2,v3,v4,v5,v6,6,SORT,POP,5,REV,POP,+,+,+,4,/
→ v1 부터 v6중에서 최대/최소값 한개씩을 삭제한 후 평균을 구함
UNKN
: 스택에 "Unknown" 값을 푸시INF
, NEGINF
: 스택에 "Infinite", "Negative Infinite"을 푸시한다.PREV
: 이전값을 푸시한다 PREV(vname)
: 특정한 변수의 이전값을 푸시한다. 이전값이 없으면(첫번째 타임스탭이라면) Unknown 을 푸시한다.COUNT
: 스택에 있는 변수의 개수 + 1 를 리턴한다.RRDtool 에서 시간은 타임스탬프다.
NOW
: 현재 시간을 스택에 넣는다.STEPWIDTH
: 현재 시간 단위 값을 푸시한다. 단위는 초이다.NEWDAY
, NEWWEEK
, NEWMONTH
, NEWYEAR
: 지정한 시점의 첫번째 값인 경우 1.0을 리턴한다. 예를 들어 CDEF:mtotal=rate,STEPWIDTH,*,NEWMONTH,0,PREV,IF,ADDNAN
와 같이 사용할 수 있다.TIME
: 현재 처리중인 시간을 스택에 넣는다.LTIME
: 현재 처리중인 시간을 로컬 타임으로 변경해 스택에 넣는다.DUP
, POP
, EXC
: 최상의 요소를 복제, 삭제, 상위 2개의 요소를 교체DEPTH
: 현재 스택의 깊이를 푸시n,COPY
: 상위 n개의 요소를 복제n,INDEX
: 위에서 n번째의 요소를 복제n,m,ROLL
: 상위 n개의 요소를 로테이트VDEF
구문에서만 사용할 수 있는 몇가지 변수가 있다.
MAXIMUM
, MINIMUM
, AVERAGE
: 제공된 데이터셋의 최대, 최소, 평균값을 알려준다.STDEV
: 제공된 데이터셋의 표준편차를 알려준다.LAST
, FIRST
: 제공된 데이터셋의 마지막값 및 첫번째값을 알려준다.TOTAL
: 제공된 데이터 셋의 총합을 알려준다.PERCENT
, PERCENTNAN
: 비율. DEF 또는 CDEF 구문 바로 뒤에 나올 수 있다. (PERCENTNAN 는 Unknown 값을 무시해 계산한다)LSLSLOPE
, LSLINT
, LSLCORREL
: 제공된 데이터 셋에 대해 LSL을 알려준다. 수식으로 표현하자면 y = mx + b
에 해당된다. LSLSLOPE는 slope 값 (m
), LSLINT는 y-intercept 값 (b
), LSLCORREL는 상관계수(Correlation Coefficient)를 돌려준다.이제 .rrd
파일에 저장된 데이터를 가지고 그래프를 그릴 차례다. 아래와 같이 실행해보자.
windy@wl ~ $ rrdtool graphv load-day.png \ --title "Load Average" \ --vertical-label "# of procs in run q" \ --start -1d \ --width 400 \ --height 100 \ --lower-limit 0 \ --units-exponent 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ --zoom=2 \ "DEF:1min=load.rrd:1min:AVERAGE" \ "DEF:5min=load.rrd:5min:AVERAGE" \ "DEF:15min=load.rrd:15min:AVERAGE" \ "CDEF:c1min=1min" \ "CDEF:c5min=5min" \ "CDEF:c15min=15min" \ "AREA:c1min#54EC48:1 MIN" \ "LINE:c5min#4D18E4:5 MIN" \ "LINE:c15min#DE48EC:15 MIN" graph_left = 67 graph_top = 28 graph_width = 400 graph_height = 100 image_width = 482 image_height = 168 graph_start = 1551061612 graph_end = 1551148012 value_min = 0.0000000000e+00 value_max = 2.3145188000e+00 legend[0] = " 1 MIN" coords[0] = "16,148,65,161" legend[1] = " 5 MIN" coords[1] = "213,148,262,161" legend[2] = " 15 MIN" coords[2] = "410,148,466,161"아래와 유사한 그래프가 그려질 것이다.
그래프를 그릴 때 몇가지 유용한 옵션에 대해 설명한다.
--title
: 제목을 정의한다.--vertical-label
: 세로로 된 레이블을 정의한다.--start
: 그래프의 시작 위치를 정의한다. -1d는 1일 전을 의미한다. 이외는 별개로 --end
를 지정해 그래프의 종료 위치를 정의할 수 있다.--width
, --height
: 그래프의 너비와 높이를 지정한다. 생성되는 이미지는 그래프 외에 타이틀과 범례를 포함하기 때문이 이보다 크며, 실제 이미지 크기는 이 명령의 출력값이다. (481px X 173px)--lower-limit
: 최저값을 정의한다. 로드 평균은 0이 최저값이기 때문에 0으로 정의한다.--upper-limit
: 최대값을 정의한다. 로드 평균의 최대값은 정해지지 않았기 때문에 지정하지 않는다.--logarithmic
: 플롯에 로그함수를 사용한다. 값의 편차가 클 때 사용해볼만 하다.--base
: 기본배수가 되는 값을 지정한다. 지정하지 않으면 1000이다. 메모리의 양이나 디스크및 볼륨의 양을 표시할 때에는 1024로 지정해야 한다. 네트워크 트래픽을 포함한 그외의 경우는 1000으로 지정해야 한다.--rigid
: 지정한 상한과 하한값을 사용해 그래프를 그린다. 그래프가 오버런 되도록 한다.--units-exponent
: 사용할 유닛의 배수를 지정한다. 0은 비활성화 시킨다. 로드 평균은 k, m, g 등으로 변환하지 않고 그대로 보여주는 것이 좋기 때문에 0으로 세팅한다.--alt-autoscale-max
: 최대값을 계산하는 알고리즘을 기본 알고리즘이 아닌 다른 알고리즘을 사용하도록 한다. 좀 더 자세하게 계산하지만, 약간 더 느려진다. 필자의 생각으로는 감안할 수 있는 범위로 생각한다.--disable-rrdtool-tag
: 그래프 오른쪽의 rrdtool 태그를 출력하지 않는다.--zoom
: 주어진 값 만큼 확대. 높은 DPI를 가진 디스플레이에서 그래프를 봐야할 때 이 옵션을 주어야 한다.DEF
: 데이터를 정의한다. 아래와 같은 구문을 가진다.
DEF:<vname>=<rrdfile>:<ds-name>:<CF>[:step=<step>][:start=<time>][:end=<time>][:reduce=<CF>][:daemon=<address>]예를 들어
DEF:5mind=load.rrd:5min:LAST
의 의미는 load.rrd
파일에서, DS=5min 및 RRA=LAST로 저장된 데이터를
5mind로 정의한다.
VDEF
: 가상 데이터를 정의한다. 아래와 같은 구문을 가진다.
VDEF:vname=RPN expression예를 들어
VDEF:xa=x,AVERAGE
의 의미는 x의 평균값을 구한다.
CDEF
: 정의된 데이터를 RPN식을 사용해 수정한다. 아래와 같은 구문을 가진다.
CDEF:vname=RPN expression위의 예제에서는 변환하지 않고 그대로 사용하지만, 데이터를 변환할 수 있다. 예를 들어 5mind 값에 20을 더한후 10을 곱하고 싶다면
(5mind + 20) × 10이므로
CDEF:c5mind=5mind,20,+,10,*
와 같이 적으면 된다.LINE
: 데이터를 선으로 그린다. 아래와 같은 구문을 가진다.
LINE[width]:value[#color][:[legend][:STACK][:skipscale][:dashes[=on_s[,off_s[,on_s,off_s]...]][:dash-offset=offset]]]예를 들어
LINE:5mind#C0FFC0:5MIN
의 의미는 5mind로 정의된 데이터를
#C0FFC0(■) 색상으로 LINE을 그리고,
5MIN이라 명명한다.
AREA
: 데이터를 영역으로 그린다. 아래와 같은 구문을 가진다.
AREA:value[#color][:[legend][:STACK][:skipscale]]예를 들어
AREA:15mind#C0C0C0:15MIN
의 의미는 15mind로 정의된 데이터를
#C0C0C0(■)색상으로
AREA형식으로 그리고,
15MIN이라 명명한다.
TICK
: 틱 영역을 그린다. 아래와 같은 구문을 가진다.
TICK:vname#rrggbb[aa][:fraction[:legend]]예를 들어
TICK:value#FFFFA0
의 의미는 value 이 0이 아니고 Unknown 이 아닌 경우 #FFFFA0(■)색상의 수직 라인을 그린다.
STACK
: STACK
구문은 사용하지 않는다. 기존에는 AREA
형식으로 쌓아올리는 그래프를 그리는 구문이었으나, 현재는 LINE, AREA 구문에 통합되어있다.~/.fonts
에 폰트 파일(.ttf)을 넣어 설정하면 된다. 그래프를 그릴때 사용하는 폰트를 바꾸려면, RRD_DEFAULT_FONT
환경변수를 설정한다. RRD_DEFAULT_FONT="sample.ttf"
과 같이 설정하고 sample.ttf
파일을 ~/.fonts
에 넣으면 된다.RRA:AVERAGE:0.5:1:1440
으로 그래프를 그릴 것이다.
RRDtool 에서는 LSLSLOPE, LSLINT 식을 사용해 미래의 예측 데이터를 그릴 수 있다. (하기 예제에서 rrdtool_volstat_rpool.rrd
파일은 문서 하단에 설명되어있는 rrdtool_volstat.sh
스크립트를 사용해 생성한 파일이다)
windy@wl ~ $ export FN="rrdtool_volstat_rpool.rrd" windy@wl ~ $ rrdtool graph rrdtool_lsl.png \ --start -4w \ --end +4w \ --vertical-label "Volume Usage" \ --title "Volume Usage root@wl" \ --width 500 \ --height 100 \ --base 1024 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:TOTAL=$FN:TOTAL:AVERAGE" \ "DEF:USAGE=$FN:USAGE:AVERAGE:start=-8w" \ "CDEF:CTOTAL=TOTAL,1024,*" \ "CDEF:CUSAGE=USAGE,1024,*" \ "CDEF:CTOTAL60=TOTAL,0.6,*,1024,*" \ "CDEF:CAREAW=CUSAGE,CTOTAL60,GT,CUSAGE,0,IF" \ "CDEF:CAREAU=CUSAGE,CTOTAL60,GT,CTOTAL60,CUSAGE,IF" \ "VDEF:DLSL=CUSAGE,LSLSLOPE" \ "VDEF:HLSL=CUSAGE,LSLINT" \ "CDEF:ALSL=CUSAGE,POP,DLSL,COUNT,*,HLSL,+" \ "AREA:CAREAW#EC9D48" \ "AREA:CAREAU#68E4FC" \ "LINE:CUSAGE#1598C3:root Usage" \ "GPRINT:CUSAGE:AVERAGE:%.1lf %S" \ "LINE:CTOTAL#CC3118:root Total" \ "GPRINT:CTOTAL:AVERAGE:%.1lf %S" \ "LINE:ALSL#B415C7:root Usage Pred:dashes=5"
강조된 부분이 LSL 예측에 필요한 파라메터들이다. 아래와 유사한 그래프가 생성되며, 분홍 점선이 LSL 을 사용해 예측한 값이다. 현재 시간 이후 4주차까지 예측해 그렸다.
LSL외에도 PREDICT 식을 사용해 미래의 예측 데이터를 그릴 수 있다. (하기 예제에서 rrdtool_net_net.rrd
파일은 문서 하단에 설명되어있는 rrdtool_net.sh
스크립트를 사용해 생성한 파일이다)
windy@wl ~ $ export FN="rrdtool_net_net.rrd" windy@wl ~ $ rrdtool graph rrdtool_predict.png \ --start=-4w \ --end=+1w \ --vertical-label "bytes/s" \ --title "Network Traffics " \ --width 500 \ --height 100 \ --alt-autoscale-max \ --disable-rrdtool-tag \ DEF:value=$FN:bytes_in:AVERAGE:start=-8w \ LINE1:value#ff0000:bytes_in \ CDEF:predict=86400,-7,1800,value,PREDICT \ CDEF:sigma=86400,-7,1800,value,PREDICTSIGMA \ CDEF:upper=predict,sigma,3,*,+ \ CDEF:lower=predict,sigma,3,*,- \ LINE1:predict#00ff00:prediction \ LINE1:upper#0000ff:upper\ certainty\ limit \ LINE1:lower#0000ff:lower\ certainty\ limit \ CDEF:exceeds=value,UN,0,value,lower,upper,LIMIT,UN,IF \ TICK:exceeds#aa000080:1 \ CDEF:perc95=86400,-7,1800,95,value,PREDICTPERC \ LINE1:perc95#ffff00:95th_percentile
아래와 유사한 그래프가 생성된다. Week 14 까지가 데이터가 있는 구간이고, 그이후 구간중 초록색 선이 예측된 값, 파란색 선이 오차 범위를 나타내었다.
그래프상으로는 오차 구간이 크기 때문에 음수까지 나오는데, 이를 없애면 아래와 같이 그려진다. CDEF:lower=predict,sigma,3,*,- \
대신 CDEF:lower=predict,sigma,3,*,-,0,MAX \
를 사용했다.
HWPREDICT 지시자를 사용한 운전일탈 감지를 위한 그래프 예시다. 다른 예제와는 달리 RRA 에 HWPREDICT가 사전에 지정되어 있어야 한다.(하기 예제에서 rrdtool_net_net.rrd
파일은 문서 하단에 설명되어있는 rrdtool_net.sh
스크립트를 사용해 생성한 파일이다)
windy@wl ~ $ export FN="rrdtool_net_net.rrd" windy@wl ~ $ rrdtool graph rrdtool_hwpredict.png \ --start -1d \ --vertical-label "bytes/s" \ --title "Network Traffics " \ --width 500 \ --height 100 \ --alt-autoscale-max \ --disable-rrdtool-tag \ --lower-limit 0 \ "DEF:bi=$FN:bytes_in:AVERAGE" \ "DEF:bipred=$FN:bytes_in:HWPREDICT" \ "DEF:bidev=$FN:bytes_in:DEVPREDICT" \ "DEF:bifail=$FN:bytes_in:FAILURES" \ "DEF:bo=$FN:bytes_out:AVERAGE" \ "DEF:bopred=$FN:bytes_out:HWPREDICT" \ "DEF:bodev=$FN:bytes_out:DEVPREDICT" \ "DEF:bofail=$FN:bytes_out:FAILURES" \ "CDEF:gbi=bi" \ "CDEF:gbo=bo" \ "CDEF:biupper=bipred,bidev,2,*,+" \ "CDEF:bilower=bipred,bidev,2,*,-" \ "CDEF:boupper=bopred,bodev,2,*,+" \ "CDEF:bolower=bopred,bodev,2,*,-" \ "TICK:bifail#FFFFA0:1.0" \ "TICK:bofail#FFFFA0:1.0" \ "LINE:biupper#FFC0C0:Input Upper" \ "LINE:bilower#FFC0C0:Input Lower" \ "LINE:boupper#00C000:Output Upper" \ "LINE:bolower#00C000:Output Lower" \ "AREA:gbi#FF8080:Input bytes/s" \ "GPRINT:bi:AVERAGE:%.1lf %S" \ "LINE:gbo#00A000:Output bytes/s" \ "GPRINT:bo:AVERAGE:%.1lf %S"
아래와 유사한 그래프가 나온다. 문제가 있다고 판단되는 경우 (범위를 벗어나는 경우) TICK
커맨드에 의해 노란색 배경으로 출력된다.
.rrd
파일에 대한 캐시를 제공해주는 데몬이다. 특히 그래프를 그리기 위해 데이터를 읽을때 이로 인한 디스크 부하를 방지해준다. 이 데몬은 RRDtool 1.4 이상에 포함되어있다.windy@wl ~ $ /opt/rrdtool/bin/rrdcached -p /tmp/rrdcached.pid -b /export/home/windy/rrdtoolpid 파일을
/tmp/rrdcached.pid
에 생성하고, 나머지는 모두 기본값으로 두었다. 소켓은 Unix Domain Socket 형태로 /tmp/rrdcached.sock
에 생성된다. 자세한 사항은 RRDtool - rrdcached를 읽어보자.
unix:/tmp/rrdcached.sock
--daemon
옵션을 사용해 RRDCache 데몬을 지정할 수 있다. RRDCACHED_ADDRESS
환경변수를 지정하면 RRDtool에서 자동으로 읽어와 데몬으로 지정된다.
windy@wl ~ $ export RRDCACHED_ADDRESS="unix:/tmp/rrdcached.sock" windy@wl ~ $ rrdtool graph ...
rrdtool flushcached
명령은 메모리에 캐시된 데이터를 .rrd 파일에 쓴다. 자세한 사항은 rrdflushcached(1)을 읽어보자.windy@wl ~ $ rrdtool flushcached --daemon unix:/tmp/rrdcached.sock load.rrd
rrdtool list
명령은 RRDCached 의 캐시 목록을 알려준다.windy@wl ~ $ rrdtool list / rrdtool_load.rrd rrdtool_mem.rrd ...
저장 단위 시간 | 1분 | 5분 | 30분 | 2시간 | 1일 |
---|---|---|---|---|---|
저장 회수 | 1440 | 1440 | 800 | 800 | 800 |
총 저장 기간 1) | 1일 | 5일 | 16일 | 66일 | 2년 |
그래프 2) | 1일 | X 3) | 1주일 | 1달 | 1년 |
저장하는기간=그래프로그리는기간 × 2이다.
-1d
를 -2d
로 변경하기만 하면 된다. 개요 형식의 큰 그래프를 그릴 때 사용하면 알맞다고 생각한다.
~/rrdtool
디렉토리를 만들고 스크립트를 다운로드 받은 후 cron 에 1분마다 실행되도록 하면 설치는 완료된다.
windy@wl ~/rrdtool $ crontab -e * * * * * /export/home/windy/rrdtool/rrd.sh windy@wl ~/rrdtool $ cat rrd.sh #!/bin/bash cd ~/rrdtool #export RRDCACHED_ADDRESS="unix:/tmp/rrdcached.sock" ./rrdtool_load.sh ./rrdtool_net.sh ... windy@wl ~/rrdtool $ ls -alF -rwxr-xr-x 1 windy staff 313 4월 7일 00:00 rrd.sh* -rwxr-xr-x 1 windy staff 2647 4월 7일 00:00 rrdtool_net.sh* -rwxr-xr-x 1 windy staff 2101 4월 7일 00:00 rrdtool_load.sh* ... windy@wl ~/rrdtool $ ./rrd.sh windy@wl ~/rrdtool $ ls -alF *.rrd -rw-r--r-- 1 windy staff 172168 4월 7일 00:01 rrdtool_dskstat_sd0.rrd -rw-r--r-- 1 windy staff 129296 4월 7일 00:01 rrdtool_load.rrd -rw-r--r-- 1 windy staff 343656 4월 7일 00:01 rrdtool_mem.rrd -rw-r--r-- 1 windy staff 858120 4월 7일 00:01 rrdtool_mysql.rrd -rw-r--r-- 1 windy staff 295336 4월 7일 00:01 rrdtool_net_iprb0.rrd -rw-r--r-- 1 windy staff 86424 4월 7일 00:01 rrdtool_volstat_rpool.rrd ...
rrdtool_load.sh | (2,836 바이트) |
#!/bin/bash # Monitoring load average for Solaris, Linux # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2014.12.10 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi MI=`date +'%M'` MI=$(expr $MI + 0) HR=`date +'%H'` HR=$(expr $HR + 0) let MOD5=$MI%5; let MOD30=$MI%30; # /tmp/rrdtool_load file format # 1min load average:5min load average, 15min load average # ex) 1.00:0.50:0.10 # TEMPFN="/tmp/rrdtool_load_$$" uptime | sed -e 's/^.*load average.*: //' -e 's/ //g' | awk -F, "{ printf(\"%f:%f:%f\", \$1, \$2, \$3)}" > $TEMPFN DATA=`cat $TEMPFN` rm $TEMPFN FNPREFIX="rrdtool_load" FNRRD="$FNPREFIX.rrd" OS=`uname -s` if [ "$OS" == "SunOS" ]; then CPUCOUNT=`kstat -m cpu_info -p | grep state | grep on-line | wc -l` UPTIME=`kstat -p unix:0:system_misc:snaptime | awk '{print $2}' | awk -F. '{print $1}'` elif [ "$OS" == "Linux" ]; then CPUCOUNT=`grep -c processor /proc/cpuinfo` UPTIME=`cat /proc/uptime | awk '{print $1}' | awk -F. '{print $1}'` else CPUCOUNT=2 UPTIME=1 fi LOADWARNING=`expr $CPUCOUNT "*" 4` DATA="$DATA:$UPTIME" if [ ! -f $FNRRD ]; then rrdtool create $FNRRD \ --step 60 \ "DS:1min:GAUGE:600:0:U" \ "DS:5min:GAUGE:600:0:U" \ "DS:15min:GAUGE:600:0:U" \ "DS:uptime:GAUGE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi $RRDTOOL_BIN update $FNRRD N:$DATA function graphLoad { FIRST=`rrdtool fetch --start $1 $FNPREFIX.rrd AVERAGE | grep -v "nan" | grep ":" | head -1 | awk -F: '{print $1}'` if [ "$FIRST" == "" ]; then FIRST=`nawk 'BEGIN {print srand()}'` fi $RRDTOOL_BIN graph ${FNPREFIX}_$2.png \ --start $1 \ --vertical-label "# of threads in run q" \ --title "Load averages ($HOSTNAME)" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --units-exponent 0 \ --disable-rrdtool-tag \ "DEF:1mind=$FNRRD:1min:AVERAGE" \ "DEF:5mind=$FNRRD:5min:AVERAGE" \ "DEF:15mind=$FNRRD:15min:AVERAGE" \ "CDEF:fail=1mind,UN,TIME,$FIRST,GT,1,0,IF,0,IF" \ "COMMENT:Current " \ "GPRINT:1mind:LAST:%.2lf" \ "GPRINT:5mind:LAST:%.2lf" \ "GPRINT:15mind:LAST:%.2lf" \ "LINE:1mind#54EC48:1 MIN" \ "LINE:5mind#4D18E4:5 MIN" \ "LINE:15mind#DE48EC:15 MIN" \ "HRULE:$LOADWARNING#FF0000" \ "TICK:fail#FFFF80:1.0" \ > /dev/null } if [ "$MOD5" == "0" ]; then graphLoad -1d day fi if [ "$MOD30" == "0" ]; then graphLoad -1w week fi if [ "$MI" == "0" ]; then graphLoad -1m month fi if [ "$HR" == "0" ]; then graphLoad -1y year fi
rrdtool_cpu.sh | (7,613 바이트) |
#!/bin/bash # Monitoring CPU for Solaris # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2014.12.10 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi MI=`date +'%M'` MI=$(expr $MI + 0) HR=`date +'%H'` HR=$(expr $HR + 0) let MOD5=$MI%5; let MOD30=$MI%30; FNPREFIX="rrdtool_cpu" FNSUFFIX=".rrd" CPUCOUNT=`kstat -m cpu_info -p | grep state | grep on-line | wc -l` i=0 while [ "$i" -lt $CPUCOUNT ]; do FN=${FNPREFIX}_${i}$FNSUFFIX if [ ! -f $FN ]; then rrdtool create $FN \ --step 60 \ "DS:uptime:GAUGE:600:0:U" \ "DS:idle:DERIVE:600:0:U" \ "DS:user:DERIVE:600:0:U" \ "DS:kernel:DERIVE:600:0:U" \ "DS:wait:DERIVE:600:0:U" \ "DS:wait_io:DERIVE:600:0:U" \ "DS:wait_pio:DERIVE:600:0:U" \ "DS:wait_swap:DERIVE:600:0:U" \ "DS:iowait:DERIVE:600:0:U" \ "DS:pswitch:DERIVE:600:0:U" \ "DS:inv_swtch:DERIVE:600:0:U" \ "DS:syscall:DERIVE:600:0:U" \ "DS:sysread:DERIVE:600:0:U" \ "DS:syswrite:DERIVE:600:0:U" \ "DS:sysfork:DERIVE:600:0:U" \ "DS:sysvfork:DERIVE:600:0:U" \ "DS:sysexec:DERIVE:600:0:U" \ "DS:cow_fault:DERIVE:600:0:U" \ "DS:as_fault:DERIVE:600:0:U" \ "DS:prot_fault:DERIVE:600:0:U" \ "DS:hat_fault:DERIVE:600:0:U" \ "DS:softlock:DERIVE:600:0:U" \ "DS:kernel_asflt:DERIVE:600:0:U" \ "DS:maj_fault:DERIVE:600:0:U" \ "DS:intr:DERIVE:600:0:U" \ "DS:intrblk:DERIVE:600:0:U" \ "DS:intrthread:DERIVE:600:0:U" \ "DS:msg:DERIVE:600:0:U" \ "DS:sema:DERIVE:600:0:U" \ "DS:namei:DERIVE:600:0:U" \ "DS:cpumigrate:DERIVE:600:0:U" \ "DS:xcalls:DERIVE:600:0:U" \ "DS:trap:DERIVE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi STATI="cpu_stat:$i:" # /usr/include/sys/sysinfo.h uptime=`kstat -p unix:0:system_misc:snaptime | awk '{print $2}' | awk -F. '{print $1}'` DATA=`kstat -p \ $STATI:idle $STATI:user $STATI:kernel $STATI:wait $STATI:wait_io $STATI:wait_pio $STATI:wait_swap $STATI:iowait \ $STATI:pswitch $STATI:inv_swtch \ $STATI:syscall $STATI:sysread $STATI:syswrite $STATI:sysfork $STATI:sysvfork $STATI:sysexec \ $STATI:cow_fault $STATI:as_fault $STATI:prot_fault $STATI:hat_fault $STATI:softlock $STATI:kernel_asflt $STATI:maj_fault \ $STATI:intr $STATI:intrblk $STATI:intrthread \ $STATI:msg $STATI:sema \ $STATI:namei \ $STATI:cpumigrate $STATI:xcalls $STATI:trap \ | awk '{print $2}' \ | sed -n -e 'N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;N;s/\n/\:/g;p' \ ` DATA=$uptime:$DATA $RRDTOOL_BIN update $FN N:$DATA if [ "$?" != "0" ]; then echo "Cannot update $FN by previous error."; exit; fi function graphCpu { $RRDTOOL_BIN graph ${FNPREFIX}_${i}_utl_$2.png \ --start $1 \ --vertical-label "Util %" \ --title "CPU $i Utilization" \ --width 500 \ --height 100 \ --lower-limit 0 \ --upper-limit 100 \ --rigid \ --disable-rrdtool-tag \ "DEF:idle=$FN:idle:AVERAGE" \ "DEF:user=$FN:user:AVERAGE" \ "DEF:kernel=$FN:kernel:AVERAGE" \ "DEF:wait=$FN:wait:AVERAGE" \ "CDEF:totaltick=idle,user,+,kernel,wait,+,+" \ "CDEF:pkernel=kernel,100,*,totaltick,/" \ "CDEF:puser=user,100,*,totaltick,/" \ "CDEF:pwait=wait,100,*,totaltick,/" \ "CDEF:pidle=100,pkernel,-,puser,-,pwait,-" \ "AREA:pkernel#7648EC:Kernel" \ "AREA:puser#EA644A:User:STACK" \ "AREA:pwait#54EC48:Wait:STACK" \ "AREA:pidle#68E4FC:Idle:STACK" \ "LINE:100#1598C3" \ > /dev/null # 'totaltick' always 100 on Solaris System. see hires_tick on Solaris Tunable Parameters Reference Manual $RRDTOOL_BIN graph ${FNPREFIX}_${i}_sys_$2.png \ --start $1 \ --vertical-label "Total syscall/s" \ --title "CPU $i System Calls" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label 'Operations/s' \ --right-axis 0.01:0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:syscall=$FN:syscall:AVERAGE" \ "DEF:sysread=$FN:sysread:AVERAGE" \ "DEF:syswrite=$FN:syswrite:AVERAGE" \ "DEF:sysfork=$FN:sysfork:AVERAGE" \ "DEF:sysvfork=$FN:sysvfork:AVERAGE" \ "DEF:sysexec=$FN:sysexec:AVERAGE" \ "CDEF:csysread=sysread,20,*" \ "CDEF:csyswrite=syswrite,20,*" \ "CDEF:csysfork=sysfork,20,*" \ "CDEF:csysvfork=sysvfork,20,*" \ "CDEF:csysexec=sysexec,20,*" \ "LINE:syscall#48C4EC:total" \ "LINE:csysread#ECD748:read" \ "LINE:csyswrite#54EC48:write" \ "LINE:csysfork#EA644A:fork" \ "LINE:csysvfork#DE48EC:vfork" \ "LINE:csysexec#EC9D48:exec" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}_${i}_xcl_$2.png \ --start $1 \ --vertical-label "cpumig,xcall/s" \ --title "CPU $i xcall/migration" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label 'traps/s' \ --right-axis 100:0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:xcalls=$FN:xcalls:AVERAGE" \ "DEF:cpumigrate=$FN:cpumigrate:AVERAGE" \ "DEF:trap=$FN:trap:AVERAGE" \ "CDEF:ctrap=trap,100,/" \ "LINE:cpumigrate#EA644A:cpu migrations" \ "LINE:xcalls#24BC14:xcalls" \ "LINE:ctrap#DE48EC:traps" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}_${i}_sch_$2.png \ --start $1 \ --vertical-label "Context Switches/s" \ --title "CPU $i Context Switches" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:inv_swtch=$FN:inv_swtch:AVERAGE" \ "DEF:pswitch=$FN:pswitch:AVERAGE" \ "AREA:pswitch#68E4FC:Total Context Switches" \ "LINE:pswitch#1598C3" \ "AREA:inv_swtch#4D18E4:Involuntary Context Switches" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}_${i}_ipc_$2.png \ --start $1 \ --vertical-label "operations/s" \ --title "CPU $i IPC" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:msg=$FN:msg:AVERAGE" \ "DEF:sema=$FN:sema:AVERAGE" \ "LINE:msg#EA644A:Message count" \ "AREA:sema#24BC14:Semaphore operations" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}_${i}_int_$2.png \ --start $1 \ --vertical-label "operations/s" \ --title "CPU $i Interrupts" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:intr=$FN:intr:AVERAGE" \ "DEF:intrblk=$FN:intrblk:AVERAGE" \ "DEF:intrthread=$FN:intrthread:AVERAGE" \ "LINE:intr#EA644A:Interrupts" \ "LINE:intrblk#24BC14:Interrupts Blk" \ "LINE:intrthread#DE48EC:Interrupts Thread" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}_${i}_flt_$2.png \ --start $1 \ --vertical-label "operations/s" \ --title "CPU $i Faults" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:maj_fault=$FN:maj_fault:AVERAGE" \ "DEF:cow_fault=$FN:cow_fault:AVERAGE" \ "DEF:as_fault=$FN:as_fault:AVERAGE" \ "DEF:prot_fault=$FN:as_fault:AVERAGE" \ "DEF:softlock=$FN:as_fault:AVERAGE" \ "LINE:maj_fault#EA644A:Major Faults" \ "LINE:cow_fault#24BC14:COW Faults" \ "LINE:as_fault#DE48EC:AS Faults" \ "LINE:prot_fault#EC9D48:Protection Faults" \ "LINE:softlock#48C4EC:Soft Lock" \ > /dev/null } if [ "$MOD5" == "0" ]; then graphCpu -1d day fi if [ "$MOD30" == "0" ]; then graphCpu -1w week fi if [ "$MI" == "0" ]; then graphCpu -1m month fi if [ "$HR" == "0" ]; then graphCpu -1y year fi i=`echo $i + 1 | bc`; done
rrdtool_net.sh | (5,499 바이트) |
#!/bin/bash # Monitoring network traffic/packets for solaris # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2011.12.10 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi MI=`date +'%M'` MI=$(expr $MI + 0) HR=`date +'%H'` HR=$(expr $HR + 0) let MOD5=$MI%5; let MOD30=$MI%30; # /tmp/rrdtool_net file format # InterfaceName InputPackets OutputPackets InputBytes OutputBytes InterfaceSpeed per each line. # -> e1000g0 ipackets obytes opackets rbytes ifspeed # Do not use 64bit integer for compatibility issue. TEMPFN="/tmp/rrdtool_net_$$" kstat -c net -p 'link:::[or]bytes' -p 'link:::[io]packets' -p 'link:::ifspeed' \ | sed '/lo/d' \ | awk 'BEGIN{FS=":"} {print $3,$4}' \ | awk '{print $1,$2,$3}' \ | sort -k 1,2 \ | sed -n -e 'N;N;N;N;s/\n/ /g;p' \ | awk '{print $1,$6,$12,$15,$9,$3}' \ > $TEMPFN cat $TEMPFN | while read LINE do IFNAME=`echo $LINE | awk '{print $1}'` DATA=`echo $LINE | awk '{print $2,$3,$4,$5}' | sed -e 's/ /:/g'` IFSPEED=`echo $LINE | awk '{print $6}'` FN="rrdtool_net_$IFNAME.rrd" if [ "$IFSPEED" == "10000000" ]; then IFSPEEDMSG="10Mbps" elif [ "$IFSPEED" == "100000000" ]; then IFSPEEDMSG="100Mbps" elif [ "$IFSPEED" == "1000000000" ]; then IFSPEEDMSG="1Gbps" elif [ "$IFSPEED" == "10000000000" ]; then IFSPEEDMSG="10Gbps" elif [ "$IFSPEED" == "40000000000" ]; then IFSPEEDMSG="40Gbps" elif [ "$IFSPEED" == "100000000000" ]; then IFSPEEDMSG="100Gbps" else IFSPEEDMSG="?" fi if [ ! -f $FN ]; then rrdtool create $FN \ --step 60 \ "DS:packets_in:DERIVE:600:0:U" \ "DS:packets_out:DERIVE:600:0:U" \ "DS:bytes_in:DERIVE:600:0:U" \ "DS:bytes_out:DERIVE:600:0:U" \ "RRA:HWPREDICT:1440:0.1:0.0035:288" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" \ "RRA:MAX:0.5:60:24" fi rrdtool update $FN N:$DATA function graphNet { rrdtool graph rrdtool_net_${IFNAME}_pks_$2.png \ --start $1 \ --vertical-label "Packets/s" \ --title "Network Traffics ${IFNAME}@$HOSTNAME ($IFSPEEDMSG)" \ --width 500 \ --height 100 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:pi=$FN:packets_in:AVERAGE" \ "DEF:po=$FN:packets_out:AVERAGE" \ "DEF:fail=$FN:packets_out:FAILURES" \ "CDEF:gpi=pi" \ "CDEF:gpo=po" \ "TICK:fail#FFFFA0:1.0" \ "AREA:gpi#FF8080:Input Packets/s" \ "GPRINT:pi:AVERAGE:%.1lf %S" \ "LINE:gpo#00A000:Output Packets/s" \ "GPRINT:po:AVERAGE:%.1lf %S" \ > /dev/null rrdtool graph rrdtool_net_${IFNAME}_bit_$2.png \ --start $1 \ --vertical-label "bytes/s" \ --title "Network Traffics ${IFNAME}@$HOSTNAME ($IFSPEEDMSG)" \ --width 500 \ --height 100 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:bi=$FN:bytes_in:AVERAGE" \ "DEF:bipred=$FN:bytes_in:HWPREDICT" \ "DEF:bidev=$FN:bytes_in:DEVPREDICT" \ "DEF:bifail=$FN:bytes_in:FAILURES" \ "DEF:bo=$FN:bytes_out:AVERAGE" \ "DEF:bopred=$FN:bytes_out:HWPREDICT" \ "DEF:bodev=$FN:bytes_out:DEVPREDICT" \ "DEF:bofail=$FN:bytes_out:FAILURES" \ "CDEF:gbi=bi" \ "CDEF:gbo=bo" \ "CDEF:biupper=bipred,bidev,2,*,+" \ "CDEF:bilower=bipred,bidev,2,*,-" \ "CDEF:boupper=bopred,bodev,2,*,+" \ "CDEF:bolower=bopred,bodev,2,*,-" \ "TICK:bifail#FFFFA0:1.0" \ "TICK:bofail#FFFFA0:1.0" \ "AREA:gbi#FF8080:Input bytes/s" \ "GPRINT:bi:AVERAGE:%.1lf %S" \ "LINE:gbo#00A000:Output bytes/s" \ "GPRINT:bo:AVERAGE:%.1lf %S" \ > /dev/null } function graphNetSumm { rrdtool graph rrdtool_net_${IFNAME}_bit_summ.png \ --start -2d \ --vertical-label "bytes/s" \ --title "Network Traffics Summary ${IFNAME}@$HOSTNAME ($IFSPEEDMSG)" \ --width 500 \ --height 150 \ --alt-autoscale-max \ --disable-rrdtool-tag \ --x-grid "HOUR:1:HOUR:6:HOUR:6:0:%H:00" \ "DEF:bi=$FN:bytes_in:AVERAGE" \ "DEF:bo=$FN:bytes_out:AVERAGE" \ "DEF:bi1w=$FN:bytes_in:AVERAGE:end=now-1w:start=end-1w" \ "DEF:bo1w=$FN:bytes_out:AVERAGE:end=now-1w:start=end-1w" \ "VDEF:bimax=bi,MAXIMUM" \ "VDEF:biavg=bi,AVERAGE" \ "VDEF:bimin=bi,MINIMUM" \ "VDEF:bomax=bo,MAXIMUM" \ "VDEF:boavg=bo,AVERAGE" \ "VDEF:bomin=bo,MINIMUM" \ "VDEF:bi1wmax=bi1w,MAXIMUM" \ "VDEF:bi1wavg=bi1w,AVERAGE" \ "VDEF:bi1wmin=bi1w,MINIMUM" \ "VDEF:bo1wmax=bo1w,MAXIMUM" \ "VDEF:bo1wavg=bo1w,AVERAGE" \ "VDEF:bo1wmin=bo1w,MINIMUM" \ "LINE:bi#EA644A:Input " \ "GPRINT:bimax:%6.1lf %S" \ "GPRINT:biavg:%6.1lf %S" \ "GPRINT:bimin:%6.1lf %S\l" \ "LINE:bi1w#EC9D48:Input (-1w)" \ "GPRINT:bi1wmax:%6.1lf %S" \ "GPRINT:bi1wavg:%6.1lf %S" \ "GPRINT:bi1wmin:%6.1lf %S\l" \ "LINE:bo#7648EC:Output " \ "GPRINT:bomax:%6.1lf %S" \ "GPRINT:boavg:%6.1lf %S" \ "GPRINT:bomin:%6.1lf %S\l" \ "LINE:bo1w#48C4EC:Output (-1w)" \ "GPRINT:bo1wmax:%6.1lf %S" \ "GPRINT:bo1wavg:%6.1lf %S" \ "GPRINT:bo1wmin:%6.1lf %S\l" \ "DEF:fail=$FN:bytes_in:FAILURES" \ "TICK:fail#000000:1.0:Fail" \ > /dev/null } if [ "$MOD5" == "0" ]; then graphNet -1d day fi if [ "$MOD30" == "0" ]; then graphNet -1w week fi if [ "$MI" == "0" ]; then graphNet -1m month fi if [ "$HR" == "0" ]; then graphNet -1y year fi # graphNetSumm done rm $TEMPFN
rrdtool_mem.sh | (3,293 바이트) |
#!/bin/bash # Monitoring memory usage for solaris # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2015.12.16 . /etc/profile PATH=/opt/rrdtool/bin:/usr/bin cd ~windy/rrdtool LANG=C # /tmp/rrdtool_mem file format # Kernel ZFS Anon ExecLib Page FreeCache FreeList Total (in pages) PAGESIZE=`pagesize` echo '::memstat' | pfexec mdb -k > /tmp/rrdtool_mem if [ "$?" != "0" ]; then echo "Must run as root priv." exit 1 fi MDBLINES=`cat /tmp/rrdtool_mem | wc -l | awk '{print $1}'` if [ "$MDBLINES" == "10" ]; then # Solaris 11.4 cat /tmp/rrdtool_mem \ | sed '1,2d' \ | sort -k 1 \ | awk '{print substr($0, 18, 100) }' \ | awk '{print $1 }' \ | sed -n -e 'N;N;N;N;N;N;N;s/\n/ /g;p' \ | awk '{print $4,$8,$7,$1,$5,$3,$2,$6}' \ > /tmp/rrdtool_mem2 elif [ "$MDBLINES" == "11" ]; then # Solaris 10 cat /tmp/rrdtool_mem \ | sed '1,2d' \ | sort -k 1 \ | awk '{print substr($0, 18, 100) }' \ | awk '{print $1 }' \ | sed -n -e 'N;N;N;N;N;N;N;N;s/\n/ /g;p' \ | awk '{print $5,$8,$1,$2,$6,$3,$4,$7}' \ > /tmp/rrdtool_mem2 elif [ "$MDBLINES" == "12" ]; then # Solaris 11 cat /tmp/rrdtool_mem \ | sed '1,2d' \ | sort -k 1 \ | awk '{print substr($0, 18, 100) }' \ | awk '{print $1 }' \ | sed -n -e 'N;N;N;N;N;N;N;N;N;s/\n/ /g;p' \ | awk '{print $6,$9 + $10,$1,$2,$7,$3,$4,$8}' \ > /tmp/rrdtool_mem2 else echo "ERROR: Cannot recognize MDB Output [$MDBLINES]" exit 1 fi rm /tmp/rrdtool_mem DATA=`cat /tmp/rrdtool_mem2 | sed -e 's/ /:/g'` rm /tmp/rrdtool_mem2 FN="rrdtool_mem.rrd" if [ ! -f $FN ]; then rrdtool create $FN \ --step 60 \ "DS:kern:GAUGE:600:0:U" \ "DS:zfsd:GAUGE:600:0:U" \ "DS:anon:GAUGE:600:0:U" \ "DS:exec:GAUGE:600:0:U" \ "DS:page:GAUGE:600:0:U" \ "DS:fcah:GAUGE:600:0:U" \ "DS:flst:GAUGE:600:0:U" \ "DS:tot:GAUGE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi rrdtool update $FN N:$DATA function graphMem { rrdtool graph rrdtool_mem_$2.png \ --start $1 \ --vertical-label "Memory Usage" \ --title "Memory Usage ($HOSTNAME)" \ --width 500 \ --height 100 \ --base 1024 \ --lower-limit 0 \ --disable-rrdtool-tag \ "DEF:kern=$FN:kern:AVERAGE" \ "DEF:zfsd=$FN:zfsd:AVERAGE" \ "DEF:anon=$FN:anon:AVERAGE" \ "DEF:exec=$FN:exec:AVERAGE" \ "DEF:page=$FN:page:AVERAGE" \ "DEF:fcah=$FN:fcah:AVERAGE" \ "DEF:flst=$FN:flst:AVERAGE" \ "DEF:tot=$FN:tot:AVERAGE" \ "CDEF:ckern=kern,$PAGESIZE,*" \ "CDEF:czfsd=zfsd,$PAGESIZE,*" \ "CDEF:canon=anon,$PAGESIZE,*" \ "CDEF:cexec=exec,$PAGESIZE,*" \ "CDEF:cpage=page,$PAGESIZE,*" \ "CDEF:cfcah=fcah,$PAGESIZE,*" \ "CDEF:cflst=flst,$PAGESIZE,*" \ "CDEF:ctot=tot,$PAGESIZE,*" \ "AREA:ckern#EA644A:Kernel" \ "AREA:canon#EC9D48:Anon:STACK" \ "AREA:cexec#ECD748:Exec:STACK" \ "AREA:cpage#54EC48:Page:STACK" \ "AREA:czfsd#48C4EC:ZFS:STACK" \ "AREA:cfcah#DE48EC:FreeCache:STACK" \ "AREA:cflst#7648EC:FreeList:STACK" \ "LINE:ctot#4D18E4:Total" \ > /dev/null } graphMem -1d day MI=`date +'%M'` if [ "$MI" -lt "5" ]; then graphMem -1w week graphMem -1m month graphMem -1y year fi
rrdtool_volstat.sh | (2,295 바이트) |
#!/bin/bash # Monitoring disk usage for solaris # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2014.03.26 PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi FNPREFIX="rrdtool_volstat_" FNCONF="rrdtool_volstat.conf" FNRRDSUFFIX=".rrd" FNGRASUFFIX=".png" if [ ! -f "$FNCONF" ]; then UFS=`mount -p | awk '{print $3}' | grep ufs` if [ -x /usr/sbin/zpool ]; then ZFS=`zpool list | sed 1d | awk '{print $1}'` fi echo "FS='$UFS $ZFS'" > $FNCONF fi . "$FNCONF" if [ "$FS" == "" ]; then echo "Cannot determine file systems." exit 1 fi for MNTPOINT in $FS; do FNRRD=$FNPREFIX$MNTPOINT$FNRRDSUFFIX if [ ! -f "$FNRRD" ]; then $RRDTOOL_BIN create "$FNRRD" \ --step 60 \ DS:TOTAL:GAUGE:600:0:U \ DS:USAGE:GAUGE:600:0:U \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi DATA=`df -k $MNTPOINT | sed 1d | awk '{print $2, $2 - $4}' | sed -e 's/ /:/g'` $RRDTOOL_BIN update $FNRRD N:$DATA function graphVol { $RRDTOOL_BIN graph ${FNPREFIX}${MNTPOINT}_$2$FNGRASUFFIX \ --start $1 \ --vertical-label "Volume Usage" \ --title "Volume Usage $MNTPOINT@$HOSTNAME" \ --width 500 \ --height 100 \ --base 1024 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:TOTAL=$FNRRD:TOTAL:AVERAGE" \ "DEF:USAGE=$FNRRD:USAGE:AVERAGE" \ "CDEF:CTOTAL=TOTAL,1024,*" \ "CDEF:CUSAGE=USAGE,1024,*" \ "CDEF:CTOTAL60=TOTAL,0.6,*,1024,*" \ "CDEF:CAREAW=CUSAGE,CTOTAL60,GT,CUSAGE,0,IF" \ "CDEF:CAREAU=CUSAGE,CTOTAL60,GT,CTOTAL60,CUSAGE,IF" \ "AREA:CAREAW#EC9D48" \ "AREA:CAREAU#68E4FC" \ "LINE:CUSAGE#1598C3:$MNTPOINT Usage" \ "GPRINT:CUSAGE:AVERAGE:%.1lf %S" \ "LINE:CTOTAL#CC3118:$MNTPOINT Total" \ "GPRINT:CTOTAL:AVERAGE:%.1lf %S" \ > /dev/null } graphVol -1d day MI=`date +'%M'` if [ "$MI" -lt "5" ]; then graphVol -1w week graphVol -1m month graphVol -1y year fi done
rrdtool_dskstat.sh | (4,374 바이트) |
#!/bin/bash # Monitoring disk activity for solaris # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2014.03.17 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi CONFFN="rrdtool_dskstat.conf" FNPREFIX="rrdtool_dskstat_" FNSUFFIX=".rrd" if [ ! -f $CONFFN ]; then DISKS=`kstat -p :::class | grep disk | grep -v unix | awk -F: '{print $3}'` echo "# Generated by rrdtool_dskstat.sh" > $CONFFN echo "# If you want add DISK INSTANCES, edit carefully, must use space as seperater." >> $CONFFN echo "DISKS='$DISKS'" >> $CONFFN fi . $CONFFN if [ "$DISKS" == "" ]; then echo "Cannot determine disks." exit 1 fi TEMPFN="/tmp/rrdtool_dskstat_status_$$" RRDCREATECMD="" DATA="" RRDGRAPHCMD="" NUM=0 for DISKID in $DISKS; do IDX=$NUM NUM=`expr $NUM + 1` FN="$FNPREFIX$DISKID$FNSUFFIX" STATI="::$DISKID" DATA=`kstat -p \ $STATI:nread $STATI:nwritten \ $STATI:reads $STATI:writes \ $STATI:rtime $STATI:wtime \ $STATI:rlentime $STATI:wlentime \ $STATI:rcnt $STATI:wcnt \ $STATI:rlastupdate $STATI:wlastupdate \ | awk '{print $2}' \ | awk -F. '{print $1}' \ | sed -n -e 'N;N;N;N;N;N;N;N;N;N;N;s/\n/\:/g;p'` if [ ! -f $FN ]; then rrdtool create $FN \ --step 60 \ "DS:NREAD:DERIVE:600:0:U" \ "DS:NWRITE:DERIVE:600:0:U" \ "DS:READ:DERIVE:600:0:U" \ "DS:WRITE:DERIVE:600:0:U" \ "DS:RTIME:DERIVE:600:0:U" \ "DS:WTIME:DERIVE:600:0:U" \ "DS:RLENTIME:DERIVE:600:0:U" \ "DS:WLENTIME:DERIVE:600:0:U" \ "DS:RCNT:GAUGE:600:0:U" \ "DS:WCNT:GAUGE:600:0:U" \ "DS:RLASTUPDATE:DERIVE:600:0:U" \ "DS:WLASTUPDATE:DERIVE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi rrdupdate $FN N:$DATA function graphDsk { rrdtool graph $FNPREFIX${DISKID}_opr_$2.png \ --start $1 \ --vertical-label "Bytes/s" \ --title "Disk Stat ${DISKID}@$HOSTNAME" \ --width 500 \ --height 100 \ --base 1024 \ --right-axis-label 'Operations/s' \ --right-axis 0.0001:0 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:NREAD=$FN:NREAD:AVERAGE" \ "DEF:NWRITE=$FN:NWRITE:AVERAGE" \ "DEF:READ=$FN:READ:AVERAGE" \ "DEF:WRITE=$FN:WRITE:AVERAGE" \ "CDEF:CNREAD=NREAD" \ "CDEF:CNWRITE=NWRITE" \ "CDEF:CREAD=READ,10000,*" \ "CDEF:CWRITE=WRITE,10000,*" \ "LINE:CNREAD#EA644A:Read bytes" \ "GPRINT:NREAD:LAST:%.1lf %S/s" \ "LINE:CNWRITE#54EC48:Write bytes" \ "GPRINT:NWRITE:LAST:%.1lf %S/s" \ "LINE:CREAD#EC9D48:Read" \ "GPRINT:READ:LAST:%.1lf" \ "LINE:CWRITE#7648EC:Write" \ "GPRINT:WRITE:LAST:%.1lf" \ > /dev/null rrdtool graph $FNPREFIX${DISKID}_que_$2.png \ --start $1 \ --vertical-label "Queue Waits" \ --title "Disk Stat Queue Waits ${DISKID}@$HOSTNAME" \ --width 500 \ --height 100 \ --base 1024 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:RCNT=$FN:RCNT:AVERAGE" \ "DEF:WCNT=$FN:WCNT:AVERAGE" \ "LINE:RCNT#EA644A:Read Queue Counts" \ "GPRINT:RCNT:LAST:%.0lf" \ "LINE:WCNT#54EC48:Write Queue Counts" \ "GPRINT:WCNT:LAST:%.0lf" \ > /dev/null rrdtool graph $FNPREFIX${DISKID}_hrt_$2.png \ --start $1 \ --vertical-label "nano seconds/s" \ --title "Disk Stat Time ${DISKID}@$HOSTNAME" \ --width 500 \ --height 100 \ --base 1024 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:RTIME=$FN:RTIME:AVERAGE" \ "DEF:WTIME=$FN:WTIME:AVERAGE" \ "DEF:RLENTIME=$FN:RLENTIME:AVERAGE" \ "DEF:WLENTIME=$FN:WLENTIME:AVERAGE" \ "CDEF:GRTIME=RTIME,1000,*" \ "CDEF:GWTIME=WTIME,1000,*" \ "LINE:RTIME#EA644A:R Time" \ "GPRINT:GRTIME:LAST:%.0lf ps/s" \ "LINE:WTIME#54EC48:W Time" \ "GPRINT:GWTIME:LAST:%.0lf ps/s" \ "LINE:RLENTIME#EC9D48:R LenTime" \ "LINE:WLENTIME#7648EC:W LenTime" \ > /dev/null } graphDsk -1d day MI=`date +'%M'` if [ "$MI" -lt "5" ]; then graphDsk -1w week graphDsk -1m month graphDsk -1y year fi done rm -f $TEMPFN
apachectl status
명령의 결과를 사용하며, 초당 요청 정보와 초당 사용량, MPM의 클라이언트 사용량을 그려주는데, mod_status
가 활성화 되어있어야 하며, lynx(1) (윈디하나의 솔라나라: lynx 참조)가 설치되어있어야 한다. mod_status
를 활성화 하는 방법은 Apache Module mod_status를 읽어보자.
rrdtool_apache.sh | (4,855 바이트) |
#!/bin/bash # Monitoring Apache for Solaris, Linux # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2014.04.07 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo 'Cannot find RRDTool. Set $RRDTOOL_BIN env.' exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi FNPREFIX="rrdtool_apache" if [ "$LYNX" == "" ]; then LYNX=`which lynx` if [ ! -x "$LYNX" ]; then echo 'Cannot run Lynx. Set $LYNX env.' exit 1 fi fi if [ "$STATUSURL" == "" ]; then STATUSURL="http://localhost/server-status" fi FN="$FNPREFIX.rrd" if [ ! -f $FN ]; then rrdtool create $FN \ --step 60 \ "DS:Accesses:DERIVE:600:0:U" \ "DS:kBytes:DERIVE:600:0:U" \ "DS:CPULoad:GAUGE:600:0:U" \ "DS:Uptime:GAUGE:600:0:U" \ "DS:ReqPerSec:GAUGE:600:0:U" \ "DS:BytesPerSec:GAUGE:600:0:U" \ "DS:BytesPerReq:GAUGE:600:0:U" \ "DS:BusyWorkers:GAUGE:600:0:U" \ "DS:IdleWorkers:GAUGE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi TMPFN=/tmp/rrdtool_apache_$$ $LYNX -dump $STATUSURL?auto > $TMPFN if [ "$?" != "0" ]; then echo "Cannot retrieve httpd status. '$STATUSURL' is invalid?"; rm $TMPFN exit 1 fi; #DATA=`cat $TMPFN | sed -n -e 'N;N;N;N;N;N;N;N;s/\n/ /g;p' | head -1 | awk '{printf("%d:%d:%f:%d:%f:%f:%f:%d:%d", $3, $6, $8, $10, $12, $14, $16, $18, $20)}'` Accesses=`cat $TMPFN | grep 'Total Accesses' | awk '{printf("%d", $3)}'` kBytes=`cat $TMPFN | grep 'Total kBytes' | awk '{printf("%d", $3)}'` CPULoad=`cat $TMPFN | grep 'Load1:' | awk '{printf("%f", $2)}'` Uptime=`cat $TMPFN | grep 'ServerUptimeSeconds' | awk '{printf("%d", $2)}'` ReqPerSec=`cat $TMPFN | grep 'ReqPerSec' | awk '{printf("%f", $2)}'` BytesPerSec=`cat $TMPFN | grep 'BytesPerSec' | tail -1 | awk '{printf("%f", $2)}'` BytesPerReq=`cat $TMPFN | grep 'BytesPerReq' | tail -1 | awk '{printf("%f", $2)}'` BusyWorkers=`cat $TMPFN | grep 'BusyWorkers' | tail -1 | awk '{printf("%d", $2)}'` IdleWorkers=`cat $TMPFN | grep 'IdleWorkers' | tail -1 | awk '{printf("%d", $2)}'` DATA="$Accesses:$kBytes:$CPULoad:$Uptime:$ReqPerSec:$BytesPerSec:$BytesPerReq:$BusyWorkers:$IdleWorkers" rm $TMPFN FACTOR=`echo $DATA | awk -F: '{print $7 / 1024}'` #FACTOR="0.01" # 484392:8276985:0.657552:776624:0.623715:10913.400000:17497.500000:1:249 # or use support/log_server_status $RRDTOOL_BIN update $FN N:$DATA if [ "$?" != "0" ]; then echo "Cannot update $FN by previous error."; exit; fi function graphApache { $RRDTOOL_BIN graph ${FNPREFIX}_sec_$2.png \ --start $1 \ --vertical-label "Requests/s" \ --title "Apache httpd Transmit status" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label 'KBytes/s' \ --right-axis $FACTOR:0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:kBytes=$FN:kBytes:AVERAGE" \ "DEF:Accesses=$FN:Accesses:AVERAGE" \ "DEF:Uptime=$FN:Uptime:AVERAGE" \ "CDEF:ckBytes=Uptime,PREV(Uptime),GT,kBytes,UNKN,IF,$FACTOR,/" \ "CDEF:cAccesses=Uptime,PREV(Uptime),GT,Accesses,UNKN,IF" \ "CDEF:gBytes=kBytes,1024,*" \ "CDEF:gAccesses=Accesses" \ "AREA:ckBytes#24BC14: Transfered/s" \ "GPRINT:gBytes:LAST:%.1lf %S" \ "LINE:cAccesses#EA644A:Requests/s" \ "GPRINT:gAccesses:LAST:%.1lf" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}_req_$2.png \ --start $1 \ --vertical-label "Bytes/Requests" \ --title "Apache httpd status" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label 'Bytes/Requests' \ --right-axis 1:0 \ --base 1024 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:BytesPerReq=$FN:BytesPerReq:AVERAGE" \ "CDEF:cBytesPerReq=BytesPerReq" \ "AREA:cBytesPerReq#68E4FC:Bytes/Requests" \ "LINE:cBytesPerReq#1598C3" \ "GPRINT:cBytesPerReq:AVERAGE:%.2lf %S" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}_worker_$2.png \ --start $1 \ --vertical-label "Workers" \ --title "Apache httpd Worker status" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label 'Workers' \ --right-axis 1:0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:BusyWorkers=$FN:BusyWorkers:AVERAGE" \ "DEF:IdleWorkers=$FN:IdleWorkers:AVERAGE" \ "CDEF:cBusyWorkers=BusyWorkers" \ "CDEF:cIdleWorkers=IdleWorkers" \ "CDEF:cTotalWorkers=IdleWorkers,BusyWorkers,+" \ "AREA:cBusyWorkers#7648EC:Busy Workers" \ "GPRINT:cBusyWorkers:AVERAGE:%.0lf" \ "AREA:cIdleWorkers#68E4FC:Idle Workers:STACK" \ "GPRINT:cIdleWorkers:AVERAGE:%.0lf" \ "LINE:cTotalWorkers#EA644A" \ > /dev/null } graphApache -1d day MI=`date +'%M'` if [ "$MI" -lt "5" ]; then graphApache -1w week graphApache -1m month graphApache -1y year fi
rrdtool_growth.sh | (2,225 바이트) |
#!/bin/bash # Monitoring File, Directory Growth for Solaris, Linux # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2014.12.10 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi MI=`date +'%M'` MI=$(expr $MI + 0) HR=`date +'%H'` HR=$(expr $HR + 0) let MOD5=$MI%5; let MOD30=$MI%30; if [ "$1" == "" ]; then echo "Usage: $0 rrdsuffix filepath[:filepath[:filepath[:filepath]]]"; exit 1; fi KEY="$1" GROWTHPATH="$2" FNPREFIX="rrdtool_growth_$KEY" FNRRD="$FNPREFIX.rrd" COLORS=("" "#EA644A" "#54EC48" "#48C4EC" "#DE48EC" "#7648EC") OIFS="$IFS" IFS=':' read -a GROWTHPATHARR <<< "$GROWTHPATH" IFS="$OIFS" N=0; for GROWTHFILE in "${GROWTHPATHARR[@]}"; do N=`expr $N + 1` FN=`basename $GROWTHFILE` if [ -f "$GROWTHFILE" ]; then GROWTHSIZE=`ls -l "$GROWTHFILE" | awk -F" " '{ print $5 }'` elif [ -d "$GROWTHFILE" ]; then GROWTHSIZE=`du -sk "$GROWTHFILE" | awk '{print $1}'` GROWTHSIZE=`expr $GROWTHSIZE "*" 1024` else GROWTHSIZE="-" fi; COLOR=${COLORS[N]} CREATEDATA="$CREATEDATA DS:file$N:DERIVE:600:0:U" GRAPHDATA="$GRAPHDATA DEF:file$N=$FNRRD:file$N:AVERAGE LINE:file$N$COLOR:$FN" DATA="$DATA:$GROWTHSIZE" done if [ ! -f $FNRRD ]; then rrdtool create $FNRRD \ --step 60 \ $CREATEDATA \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi rrdtool update $FNRRD N$DATA function graphFile { $RRDTOOL_BIN graph ${FNPREFIX}_$2.png \ --start $1 \ --vertical-label "bytes/s" \ --title "File/Directory Growth ($KEY)" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ $GRAPHDATA \ > /dev/null } graphFile -1d day if [ "$MOD5" == "0" ]; then graphFile -1d day fi if [ "$MOD30" == "0" ]; then graphFile -1w week fi if [ "$MI" == "0" ]; then graphFile -1m month fi if [ "$HR" == "0" ]; then graphFile -1y year fi
rrdtool_mysql.sh | (9,183 바이트) |
#!/bin/bash # MySQL Query usage # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2018.12.10 PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin:/usr/local/mysql/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi MI=`date +'%M'` MI=$(expr $MI + 0) HR=`date +'%H'` HR=$(expr $HR + 0) let MOD5=$MI%5; let MOD30=$MI%30; #MYSQLLOGINSTR=MySQL login command here if [ "$MYSQL_BIN" == "" ]; then MYSQL_BIN=`which mysql` fi if [ "$QUESTIONSFACTOR" == "" ]; then QUESTIONSFACTOR=2 fi if [ "$ROWSFACTOR" == "" ]; then ROWSFACTOR=100 fi # Set MySQL login string if [ "$MYSQLLOGINSTR" == "" ]; then echo Must be set MYSQLLOGINSTR env echo MYSQLLOGINSTR=\"--user=username --password=password --host==localhost --port=3306\"\; export MYSQLLOGINSTR exit 1 fi STATUSFN="/tmp/rrdtool_mysql_status_$$" GLOBALSTATUSFN="/tmp/rrdtool_mysql_globalstatus_$$" VARFN="/tmp/rrdtool_mysql_var_$$" # Get Total Questions and Queries Avg. echo "status" | $MYSQL_BIN $MYSQLLOGINSTR > $STATUSFN echo "show global status" | $MYSQL_BIN $MYSQLLOGINSTR > $GLOBALSTATUSFN echo "show variables" | $MYSQL_BIN $MYSQLLOGINSTR > $VARFN QUERIES=`echo "show global status like 'Com\_%'" | $MYSQL_BIN $MYSQLLOGINSTR | sed 1d | awk '{sum += $2} END { print sum }'` QUESTIONS=`cat $STATUSFN | grep Questions | awk -e '{print $4}'` QUERYSAVG=`cat $STATUSFN | grep "Queries per second avg" | awk -e '{print $20}'` ROWS_READ=`cat $GLOBALSTATUSFN | grep 'Innodb_rows_read' | awk -e '{print $2}'` ROWS_INSERT=`cat $GLOBALSTATUSFN | grep 'Innodb_rows_inserted' | awk -e '{print $2}'` ROWS_UPDATE=`cat $GLOBALSTATUSFN | grep 'Innodb_rows_updated' | awk -e '{print $2}'` ROWS_DELETE=`cat $GLOBALSTATUSFN | grep 'Innodb_rows_deleted' | awk -e '{print $2}'` QUERYS_SELECT=`cat $GLOBALSTATUSFN | grep 'Com_select' | head -1 | awk -e '{print $2}'` QUERYS_INSERT=`cat $GLOBALSTATUSFN | grep 'Com_insert' | head -1 | awk -e '{print $2}'` QUERYS_INSERTSELECT=`cat $GLOBALSTATUSFN | grep 'Com_insert_select' | head -1 | awk -e '{print $2}'` QUERYS_UPDATE=`cat $GLOBALSTATUSFN | grep 'Com_update' | head -1 | awk -e '{print $2}'` QUERYS_UPDATEMULTI=`cat $GLOBALSTATUSFN | grep 'Com_update_multi' | head -1 | awk -e '{print $2}'` QUERYS_DELETE=`cat $GLOBALSTATUSFN | grep 'Com_delete' | head -1 | awk -e '{print $2}'` QUERYS_DELETEMULTI=`cat $GLOBALSTATUSFN | grep 'Com_delete_multi' | head -1 | awk -e '{print $2}'` # Query Cache Supported? QCACHE=`cat $VARFN | grep 'query_cache_type' | awk -e '{print $2}'` if [ "$QCACHE" == "ON" ]; then QCACHE_TOTAL=`cat $VARFN | grep 'query_cache_limit' | awk -e '{print $2}'` QCACHE_FREE=`cat $GLOBALSTATUSFN | grep 'Qcache_free_memory' | awk -e '{print $2}'` QCACHE_TOTALBLOCK=`cat $GLOBALSTATUSFN | grep 'Qcache_total_blocks' | head -1 | awk -e '{print $2}'` QCACHE_FREEBLOCK=`cat $GLOBALSTATUSFN | grep 'Qcache_free_blocks' | head -1 | awk -e '{print $2}'` QCACHE_QUERIES=`cat $GLOBALSTATUSFN | grep 'Qcache_queries_in_cache' | head -1 | awk -e '{print $2}'` QCACHE_HIT=`cat $GLOBALSTATUSFN | grep 'Qcache_hits' | head -1 | awk -e '{print $2}'` QCACHE_NOTCACHED=`cat $GLOBALSTATUSFN | grep 'Qcache_not_cached' | head -1 | awk -e '{print $2}'` QCACHE_INSERTS=`cat $GLOBALSTATUSFN | grep 'Qcache_inserts' | head -1 | awk -e '{print $2}'` QCACHE_PRUNES=`cat $GLOBALSTATUSFN | grep 'Qcache_lowmem_prunes' | head -1 | awk -e '{print $2}'` else QCACHE_TOTAL=0 QCACHE_FREE=0 QCACHE_TOTALBLOCK=0 QCACHE_FREEBLOCK=0 QCACHE_QUERIES=0 QCACHE_HIT=0 QCACHE_NOTCACHED=0 QCACHE_INSERTS=0 QCACHE_PRUNES=0 fi rm $GLOBALSTATUSFN rm $STATUSFN rm $VARFN FNRRD="rrdtool_mysql.rrd" if [ ! -f $FNRRD ]; then $RRDTOOL_BIN create $FNRRD \ --step 60 \ "DS:queriesavg:GAUGE:120:0:U" \ "DS:questions:DERIVE:120:0:U" \ "DS:rowsread:DERIVE:120:0:U" \ "DS:rowsinsert:DERIVE:120:0:U" \ "DS:rowsupdate:DERIVE:120:0:U" \ "DS:rowsdelete:DERIVE:120:0:U" \ "DS:queriesselect:DERIVE:120:0:U" \ "DS:queriesinsert:DERIVE:120:0:U" \ "DS:queriesupdate:DERIVE:120:0:U" \ "DS:queriesdelete:DERIVE:120:0:U" \ "DS:queries:DERIVE:120:0:U" \ "DS:qcachetotal:GAUGE:120:0:U" \ "DS:qcachefree:GAUGE:120:0:U" \ "DS:qcachetotalblock:GAUGE:120:0:U" \ "DS:qcachefreeblock:GAUGE:120:0:U" \ "DS:qcachequeries:GAUGE:120:0:U" \ "DS:qcachehit:DERIVE:120:0:U" \ "DS:qcachenotcached:DERIVE:120:0:U" \ "DS:qcacheinserts:DERIVE:120:0:U" \ "DS:qcacheprunes:DERIVE:120:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi DATA=$QUESTIONS:$ROWS_READ:$ROWS_INSERT:$ROWS_UPDATE:$ROWS_DELETE:$QUERYS_SELECT:$QUERYS_INSERT:$QUERYS_UPDATE:$QUERYS_DELETE:$QUERIES CACHEDATA=$QCACHE_TOTAL:$QCACHE_FREE:$QCACHE_TOTALBLOCK:$QCACHE_FREEBLOCK:$QCACHE_QUERIES:$QCACHE_HIT:$QCACHE_NOTCACHED:$QCACHE_INSERTS:$QCACHE_PRUNES $RRDTOOL_BIN update $FNRRD N:$QUERYSAVG:$DATA:$CACHEDATA #for debug #DT=`date` #TS=`perl -e 'print time(), "\n" '` #echo $DT $TS N:$QUERYSAVG:$DATA1:$DATA1 >> /tmp/rrdtool_mysql.data function graphMySQL { $RRDTOOL_BIN graph rrdtool_mysql_query_$2.png \ --start $1 \ --alt-autoscale-max \ --vertical-label "Queries/s" \ --title "MySQL Queries ($HOSTNAME)" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label 'Questions/s' \ --right-axis $QUESTIONSFACTOR:0 \ --disable-rrdtool-tag \ "DEF:cntquestions=$FNRRD:questions:AVERAGE" \ "DEF:cntqueries=$FNRRD:queries:AVERAGE" \ "DEF:cntselect=$FNRRD:queriesselect:AVERAGE" \ "DEF:cntinsert=$FNRRD:queriesinsert:AVERAGE" \ "DEF:cntupdate=$FNRRD:queriesupdate:AVERAGE" \ "DEF:cntdelete=$FNRRD:queriesdelete:AVERAGE" \ "CDEF:cquestions=cntquestions,$QUESTIONSFACTOR,/" \ "CDEF:cquestionsgprint=cntquestions" \ "CDEF:cqueries=cntqueries" \ "CDEF:cselect=cntselect" \ "CDEF:cinsert=cntinsert" \ "CDEF:cupdate=cntupdate" \ "CDEF:cdelete=cntdelete" \ "AREA:cselect#FF9090:select" \ "AREA:cinsert#00FF00:insert:STACK" \ "AREA:cupdate#8080FF:update:STACK" \ "AREA:cdelete#FFFF00:delete:STACK" \ "LINE:cqueries#4D18E4:Queries/s" \ "GPRINT:cqueries:AVERAGE:%.1lf" \ "LINE:cquestions#A0A0A0:Questions/s" \ "GPRINT:cquestionsgprint:AVERAGE:%.1lf" \ > /dev/null $RRDTOOL_BIN graph rrdtool_mysql_rows_$2.png \ --start $1 \ --alt-autoscale-max \ --vertical-label "Rows Affected/s" \ --title "MySQL Query Rows ($HOSTNAME)" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label 'Rows read/s' \ --right-axis $ROWSFACTOR:0 \ --disable-rrdtool-tag \ "DEF:read=$FNRRD:rowsread:AVERAGE" \ "DEF:insert=$FNRRD:rowsinsert:AVERAGE" \ "DEF:update=$FNRRD:rowsupdate:AVERAGE" \ "DEF:delete=$FNRRD:rowsdelete:AVERAGE" \ "CDEF:cread=read,$ROWSFACTOR,/" \ "CDEF:cinsert=insert" \ "CDEF:cupdate=update" \ "CDEF:cdelete=delete" \ "LINE:cread#7648EC:Rows read" \ "AREA:cinsert#EA644A:Rows insert" \ "AREA:cupdate#54EC48:Rows update:STACK" \ "AREA:cdelete#48C4EC:Rows delete:STACK" \ > /dev/null if [ "$QCACHE" == "ON" ]; then $RRDTOOL_BIN graph rrdtool_mysql_cache_$2.png \ --start $1 \ --vertical-label "Cache (bytes)" \ --title "MySQL Query Cache ($HOSTNAME)" \ --width 500 \ --height 100 \ --lower-limit 0 \ --base 1024 \ --right-axis-label "Queries in cache" \ --right-axis 0.0009765625:0 \ --right-axis-format %.0lf \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:qcachetotal=$FNRRD:qcachetotal:AVERAGE" \ "DEF:qcachefree=$FNRRD:qcachefree:AVERAGE" \ "DEF:qcachequeries=$FNRRD:qcachequeries:AVERAGE" \ "CDEF:cqcachetotal=qcachetotal" \ "CDEF:cqcacheuse=qcachetotal,qcachefree,-" \ "CDEF:cqcachequeries=qcachequeries,1024,*" \ "LINE:cqcachetotal#7648EC:Cache Total" \ "AREA:cqcacheuse#54EC48:Cache Used" \ "LINE:cqcachequeries#EA644A:Queries in cache" \ > /dev/null $RRDTOOL_BIN graph rrdtool_mysql_ratio_$2.png \ --start $1 \ --vertical-label "counts/s" \ --title "MySQL Query Ratio ($HOSTNAME)" \ --width 500 \ --height 100 \ --lower-limit 0 \ --right-axis-label "counts/s" \ --right-axis 1:0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:qcachehit=$FNRRD:qcachehit:AVERAGE" \ "DEF:qcachenotcached=$FNRRD:qcachenotcached:AVERAGE" \ "DEF:qcacheinserts=$FNRRD:qcacheinserts:AVERAGE" \ "DEF:qcacheprunes=$FNRRD:qcacheprunes:AVERAGE" \ "CDEF:cqcachehit=qcachehit" \ "CDEF:cqcachenotcached=qcachenotcached" \ "CDEF:cqcacheinserts=qcacheinserts" \ "CDEF:cqcacheprunes=qcacheprunes" \ "LINE:cqcachenotcached#EA644A:Cache Miss" \ "LINE:cqcacheinserts#54EC48:Cache Inserts" \ "LINE:cqcacheprunes#DE48EC:Cache Prunes" \ "LINE:cqcachehit#7648EC:Cache Hits" \ > /dev/null fi } if [ "$MOD5" == "0" ]; then graphMySQL -1d day fi if [ "$MOD30" == "0" ]; then graphMySQL -1w week fi if [ "$MI" == "0" ]; then graphMySQL -1m month fi if [ "$HR" == "0" ]; then graphMySQL -1y year fi
rrdtool_pi.sh | (6,085 바이트) |
#!/bin/bash # Monitoring Raspberry Pi # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2016.06.18 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env or run 'sudo apt-get install rrdtool'" exit 1; fi fi if [ -f /etc/os-release ]; then ISPI=`cat /etc/os-release | grep -e "^ID=raspbian"` if [ "$ISPI" != "ID=raspbian" ]; then echo "This script run only on Raspbian" exit 1; fi else echo "This script run only on Raspbian" exit 1; fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi FNPREFIX="rrdtool_pi_" FNCONF="rrdtool_pi.conf" FNRRDSUFFIX=".rrd" FNGRASUFFIX=".png" if [ -f "$FNCONF" ]; then . "$FNCONF" fi if [ "$PI_TEMP" == "" ]; then if [ -x "/usr/bin/vcgencmd" ]; then PI_TEMP=`/usr/bin/vcgencmd measure_temp | cut -d'=' -f2 | cut -d"'" -f1` else echo "Cannot get Temp"; exit 1; fi fi if [ "$PI_MEM" == "" ]; then if [ -x "/usr/bin/free" ]; then PI_MEM=`/usr/bin/free -o | tail -2 | sed -n -e 'N;s/\n/ \:/g;p' | awk '{printf("%d:%d:%d:%d:%d:%d:%d:%d:%d", $2, $3, $4, $5, $6, $7, $9, $10, $11)}'` else echo "Cannot get MEM"; exit 1; fi fi if [ "$PI_VOLTS" == "" ]; then if [ -x "/usr/bin/vcgencmd" ]; then V1=`/usr/bin/vcgencmd measure_volts core | cut -d"=" -f2 | cut -d"V" -f1` V2=`/usr/bin/vcgencmd measure_volts sdram_c | cut -d"=" -f2 | cut -d"V" -f1` V3=`/usr/bin/vcgencmd measure_volts sdram_i | cut -d"=" -f2 | cut -d"V" -f1` V4=`/usr/bin/vcgencmd measure_volts sdram_p | cut -d"=" -f2 | cut -d"V" -f1` PI_VOLTS="$V1:$V2:$V3:$V4" else echo "Cannot get Volts"; exit 1; fi fi FNRRD_TEMP="${FNPREFIX}temp${FNRRDSUFFIX}" FNRRD_MEM="${FNPREFIX}mem${FNRRDSUFFIX}" FNRRD_VOLTS="${FNPREFIX}volts${FNRRDSUFFIX}" if [ ! -f "$FNRRD_TEMP" ]; then $RRDTOOL_BIN create "$FNRRD_TEMP" \ --step 60 \ "DS:TEMPERATURE:GAUGE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi if [ ! -f "$FNRRD_MEM" ]; then $RRDTOOL_BIN create "$FNRRD_MEM" \ --step 60 \ "DS:TOTAL:GAUGE:600:0:U" \ "DS:USED:GAUGE:600:0:U" \ "DS:FREE:GAUGE:600:0:U" \ "DS:SHARED:GAUGE:600:0:U" \ "DS:BUFFERS:GAUGE:600:0:U" \ "DS:CACHED:GAUGE:600:0:U" \ "DS:SWAPTOTAL:GAUGE:600:0:U" \ "DS:SWAPUSED:GAUGE:600:0:U" \ "DS:SWAPFREE:GAUGE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi if [ ! -f "$FNRRD_VOLTS" ]; then $RRDTOOL_BIN create "$FNRRD_VOLTS" \ --step 60 \ "DS:CORE:GAUGE:600:0:U" \ "DS:SDRAMC:GAUGE:600:0:U" \ "DS:SDRAMI:GAUGE:600:0:U" \ "DS:SDRAMP:GAUGE:600:0:U" \ "RRA:AVERAGE:0.5:1:1440" \ "RRA:AVERAGE:0.5:5:1440" \ "RRA:AVERAGE:0.5:30:800" \ "RRA:AVERAGE:0.5:120:800" \ "RRA:AVERAGE:0.5:1440:800" fi $RRDTOOL_BIN update $FNRRD_TEMP N:$PI_TEMP $RRDTOOL_BIN update $FNRRD_MEM N:$PI_MEM $RRDTOOL_BIN update $FNRRD_VOLTS N:$PI_VOLTS function graphPi { $RRDTOOL_BIN graph ${FNPREFIX}temp_$2$FNGRASUFFIX \ --start $1 \ --vertical-label "SoC ('C)" \ --title "Raspberry Pi Temperature@$HOSTNAME" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:TMP=$FNRRD_TEMP:TEMPERATURE:AVERAGE" \ "CDEF:CTEMP=TMP" \ "CDEF:CTEMP85=TMP,POP,85,0,+" \ "CDEF:CAREAW=CTEMP,CTEMP85,GT,CTEMP,0,IF" \ "CDEF:CAREAU=CTEMP,CTEMP85,GT,CTEMP85,CTEMP,IF" \ "AREA:CAREAW#CC3118" \ "AREA:CAREAU#48C4EC" \ "LINE:CTEMP#1598C3:Temprature" \ "GPRINT:CTEMP:LAST:%.1lf %S" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}mem_$2$FNGRASUFFIX \ --start $1 \ --vertical-label "Memory Usage" \ --title "Raspberry Pi Memory Usage@$HOSTNAME" \ --width 500 \ --height 100 \ --base 1024 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:TOTAL=$FNRRD_MEM:TOTAL:AVERAGE" \ "DEF:USED=$FNRRD_MEM:USED:AVERAGE" \ "DEF:FREE=$FNRRD_MEM:FREE:AVERAGE" \ "DEF:SHARED=$FNRRD_MEM:SHARED:AVERAGE" \ "DEF:BUFFERS=$FNRRD_MEM:BUFFERS:AVERAGE" \ "DEF:CACHED=$FNRRD_MEM:CACHED:AVERAGE" \ "DEF:SWAPTOTAL=$FNRRD_MEM:SWAPTOTAL:AVERAGE" \ "DEF:SWAPUSED=$FNRRD_MEM:SWAPUSED:AVERAGE" \ "DEF:SWAPFREE=$FNRRD_MEM:SWAPFREE:AVERAGE" \ "CDEF:GFREE=FREE,BUFFERS,CACHED,+,+,1024,*" \ "CDEF:CTOTAL=TOTAL,1024,*" \ "CDEF:CUSED=USED,BUFFERS,-,CACHED,-,SHARED,-,1024,*" \ "CDEF:CFREE=FREE,1024,*" \ "CDEF:CSHARED=SHARED,1024,*" \ "CDEF:CBUFFERS=BUFFERS,1024,*" \ "CDEF:CCACHED=CACHED,1024,*" \ "CDEF:CSWAPTOTAL=SWAPTOTAL,1024,*" \ "CDEF:CSWAPUSED=SWAPUSED,1024,*" \ "CDEF:CSWAPFREE=SWAPFREE,1024,*" \ "AREA:CSHARED#C9B215:Shared" \ "AREA:CUSED#ECD748:Used:STACK" \ "AREA:CBUFFERS#24BC14:Buffers:STACK" \ "AREA:CCACHED#48C4EC:Cached:STACK" \ "AREA:CFREE#1598C3:Free:STACK" \ "LINE:CSWAPTOTAL#CC3118:Swap Total" \ "LINE:CSWAPFREE#CC7016:Swap Free" \ "LINE:CTOTAL#1598C3:" \ "GPRINT:CTOTAL:LAST:Mem Total %.1lf %S" \ "GPRINT:GFREE:LAST:Mem Free %.1lf %S" \ "GPRINT:CSWAPFREE:LAST:Swap Free %.1lf %S" \ > /dev/null $RRDTOOL_BIN graph ${FNPREFIX}volts_$2$FNGRASUFFIX \ --start $1 \ --vertical-label "Volts (V)" \ --title "Raspberry Pi Volts@$HOSTNAME" \ --width 500 \ --height 100 \ --lower-limit 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:CORE=$FNRRD_VOLTS:CORE:AVERAGE" \ "DEF:SDRAMC=$FNRRD_VOLTS:SDRAMC:AVERAGE" \ "DEF:SDRAMI=$FNRRD_VOLTS:SDRAMI:AVERAGE" \ "DEF:SDRAMP=$FNRRD_VOLTS:SDRAMP:AVERAGE" \ "LINE:SDRAMC#4D18E4:SDRAM Controller" \ "LINE:SDRAMI#1598C3:SDRAM I/O" \ "LINE:SDRAMP#24BC14:SDRAM Physcal" \ "LINE:CORE#CC3118:Core" \ "GPRINT:CORE:LAST:%.3lf V" \ > /dev/null } graphPi -1d day MI=`date +'%M'` if [ "$MI" -lt "5" ]; then graphPi -1w week graphPi -1m month graphPi -1y year fi
rrdtool_temperature.sh | (2,777 바이트) |
#!/bin/bash # System Temperature Gauge # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2024.12.31 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi MI=`date +'%M'` MI=$(expr $MI + 0) HR=`date +'%H'` HR=$(expr $HR + 0) let MOD5=$MI%5; let MOD30=$MI%30; SENSORS_BIN=`which sensors` if [ "$SENSORS_BIN" == "" ]; then echo "Cannot find sensors. Install sensors. 'sudo apt-get lm-sensors' and run 'sensors-detect' " exit 1; fi PECI_TEMP=`sensors | grep "PECI Agent 0 Calibration" | awk '{print $5}'` CPU=`printf '%.1f' ${PECI_TEMP//°C}` GPU_TEMP=`nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader` GPU=`printf '%.1f' ${GPU_TEMP}` AUX_TEMP=`sensors | grep "AUXTIN0" | awk '{print $2}'` SYS=`printf '%.1f' ${AUX_TEMP//°C}` DRV_TEMP=`sensors drivetemp-scsi-0-0 -u | grep temp1_input | awk '{print $2}'` DRV=`printf '%.1f' ${DRV_TEMP//°C}` FNRRD="rrdtool_temperature2.rrd" if [ ! -f $FNRRD ]; then $RRDTOOL_BIN create $FNRRD \ --step 60 \ DS:CPU:GAUGE:600:0:U \ DS:GPU:GAUGE:600:0:U \ DS:SYS:GAUGE:600:0:U \ DS:DRV:GAUGE:600:0:U \ RRA:AVERAGE:0.5:1:1440 \ RRA:AVERAGE:0.5:5:1440 \ RRA:AVERAGE:0.5:30:800 \ RRA:AVERAGE:0.5:120:800 \ RRA:AVERAGE:0.5:1440:800 \ RRA:MAX:0.5:150:2400 fi rrdupdate $FNRRD N:$CPU:$GPU:$SYS:$DRV function graphTemp { $RRDTOOL_BIN graph rrdtool_temperature2_$2.png \ --start $1 \ --title "Temperature" \ --vertical-label "°C" \ --width 400 \ --height 100 \ --lower-limit 0 \ --units-exponent 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:CPU=$FNRRD:CPU:AVERAGE" \ "DEF:GPU=$FNRRD:GPU:AVERAGE" \ "DEF:SYS=$FNRRD:SYS:AVERAGE" \ "DEF:DRV=$FNRRD:DRV:AVERAGE" \ "CDEF:cCPU=CPU" \ "CDEF:cGPU=GPU" \ "CDEF:cSYS=SYS" \ "CDEF:cDRV=DRV" \ "LINE:cCPU#EA644A:CPU" \ "GPRINT:cCPU:LAST:%4.1lf%S°C" \ "LINE:cSYS#48C4EC:SYS" \ "GPRINT:cSYS:LAST:%4.1lf%S°C" \ "LINE:cDRV#7648EC:DRV" \ "GPRINT:cDRV:LAST:%4.1lf%S°C" \ "LINE:cGPU#24BC14:GPU" \ "GPRINT:cGPU:LAST:%4.1lf%S°C" \ "COMMENT:\\n" \ > /dev/null } graphTemp -1d day if [ "$MOD30" == "0" ]; then graphTemp -1w week fi if [ "$MI" == "0" ]; then graphTemp -1m month fi if [ "$HR" == "0" ]; then graphTemp -1y year fi
rrdtool_fan.sh | (4,688 바이트) |
#!/bin/bash # Fan RPM Gauge # WindyHana's Solanara: RRDtool # http://www.solanara.net/solanara/rrdtool # last update: 2024.12.31 FAN_COUNTS=4 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/rrdtool/bin:/opt/rrdtool/bin LANG=C if [ "$RRDTOOL_BIN" == "" ]; then RRDTOOL_BIN=`which rrdtool` if [ "$RRDTOOL_BIN" == "" ]; then echo "Cannot find RRDTool. Set $RRDTOOL_BIN env." exit 1; fi fi if [ "$RRDTOOL_HOME" != "" ]; then cd "$RRDTOOL_HOME" else cd `dirname $0` fi MI=`date +'%M'` MI=$(expr $MI + 0) HR=`date +'%H'` HR=$(expr $HR + 0) let MOD5=$MI%5; let MOD30=$MI%30; SENSORS_BIN=`which sensors` if [ "$SENSORS_BIN" == "" ]; then echo "Cannot find sensors. Install sensors. 'sudo apt-get lm-sensors' and run 'sensors-detect' " exit 1; fi # read fan rpm from sensors FAN1=`$SENSORS_BIN -u nct6793-isa-0290 | grep fan1_input | awk '{print $2}'` FAN2=`$SENSORS_BIN -u nct6793-isa-0290 | grep fan2_input | awk '{print $2}'` FAN3=`$SENSORS_BIN -u nct6793-isa-0290 | grep fan3_input | awk '{print $2}'` FAN4=`$SENSORS_BIN -u nct6793-isa-0290 | grep fan4_input | awk '{print $2}'` FAN5=U FAN6=U FAN7=U FAN8=U FNRRD="rrdtool_fan.rrd" if [ ! -f $FNRRD ]; then $RRDTOOL_BIN create $FNRRD \ --step 60 \ DS:FAN1:GAUGE:600:1:U \ DS:FAN2:GAUGE:600:1:U \ DS:FAN3:GAUGE:600:1:U \ DS:FAN4:GAUGE:600:1:U \ DS:FAN5:GAUGE:600:1:U \ DS:FAN6:GAUGE:600:1:U \ DS:FAN7:GAUGE:600:1:U \ DS:FAN8:GAUGE:600:1:U \ RRA:AVERAGE:0.5:1:1440 \ RRA:AVERAGE:0.5:5:1440 \ RRA:AVERAGE:0.5:30:800 \ RRA:AVERAGE:0.5:120:800 \ RRA:AVERAGE:0.5:1440:800 \ RRA:MAX:0.5:9999:2400 fi rrdupdate $FNRRD N:$FAN1:$FAN2:$FAN3:$FAN4:$FAN5:$FAN6:$FAN7:$FAN8 function graphFan { if [ "$FAN_COUNTS" == "4" ]; then $RRDTOOL_BIN graph rrdtool_fan_$2.png \ --start $1 \ --title "Fan" \ --vertical-label "RPM" \ --width 400 \ --height 100 \ --lower-limit 0 \ --units-exponent 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:FAN1=$FNRRD:FAN1:AVERAGE" \ "DEF:FAN2=$FNRRD:FAN2:AVERAGE" \ "DEF:FAN3=$FNRRD:FAN3:AVERAGE" \ "DEF:FAN4=$FNRRD:FAN4:AVERAGE" \ "DEF:FAN5=$FNRRD:FAN5:AVERAGE" \ "DEF:FAN6=$FNRRD:FAN6:AVERAGE" \ "DEF:FAN7=$FNRRD:FAN7:AVERAGE" \ "DEF:FAN8=$FNRRD:FAN8:AVERAGE" \ "CDEF:cFAN1=FAN1" \ "CDEF:cFAN2=FAN2" \ "CDEF:cFAN3=FAN3" \ "CDEF:cFAN4=FAN4" \ "CDEF:cFAN5=FAN5" \ "CDEF:cFAN6=FAN6" \ "CDEF:cFAN7=FAN7" \ "CDEF:cFAN8=FAN8" \ "LINE:cFAN1#EA644A:FAN1" \ "GPRINT:cFAN1:LAST:%4.0lf" \ "LINE:cFAN2#ECD748:FAN2" \ "GPRINT:cFAN2:LAST:%4.0lf" \ "LINE:cFAN3#48C4EC:FAN3" \ "GPRINT:cFAN3:LAST:%4.0lf" \ "LINE:cFAN4#7648EC:FAN4" \ "GPRINT:cFAN4:LAST:%4.0lf" \ "COMMENT:\\n" \ > /dev/null else $RRDTOOL_BIN graph rrdtool_fan_$2.png \ --start $1 \ --title "Fan" \ --vertical-label "RPM" \ --width 400 \ --height 100 \ --lower-limit 0 \ --units-exponent 0 \ --alt-autoscale-max \ --disable-rrdtool-tag \ "DEF:FAN1=$FNRRD:FAN1:AVERAGE" \ "DEF:FAN2=$FNRRD:FAN2:AVERAGE" \ "DEF:FAN3=$FNRRD:FAN3:AVERAGE" \ "DEF:FAN4=$FNRRD:FAN4:AVERAGE" \ "DEF:FAN5=$FNRRD:FAN5:AVERAGE" \ "DEF:FAN6=$FNRRD:FAN6:AVERAGE" \ "DEF:FAN7=$FNRRD:FAN7:AVERAGE" \ "DEF:FAN8=$FNRRD:FAN8:AVERAGE" \ "CDEF:cFAN1=FAN1" \ "CDEF:cFAN2=FAN2" \ "CDEF:cFAN3=FAN3" \ "CDEF:cFAN4=FAN4" \ "CDEF:cFAN5=FAN5" \ "CDEF:cFAN6=FAN6" \ "CDEF:cFAN7=FAN7" \ "CDEF:cFAN8=FAN8" \ "LINE:cFAN1#EA644A:FAN1" \ "GPRINT:cFAN1:LAST:%4.0lf" \ "LINE:cFAN2#ECD748:FAN2" \ "GPRINT:cFAN2:LAST:%4.0lf" \ "LINE:cFAN3#48C4EC:FAN3" \ "GPRINT:cFAN3:LAST:%4.0lf" \ "LINE:cFAN4#7648EC:FAN4" \ "GPRINT:cFAN4:LAST:%4.0lf" \ "COMMENT:\\n" \ "LINE:cFAN5#EC9D48:FAN5" \ "GPRINT:cFAN5:LAST:%4.0lf" \ "LINE:cFAN6#54EC48:FAN6" \ "GPRINT:cFAN6:LAST:%4.0lf" \ "LINE:cFAN7#68E4FC:FAN7" \ "GPRINT:cFAN7:LAST:%4.0lf" \ "LINE:cFAN8#DE48EC:FAN8" \ "GPRINT:cFAN8:LAST:%4.0lf" \ "COMMENT:\\n" \ > /dev/null fi } graphFan -1d day if [ "$MOD30" == "0" ]; then graphFan -1w week fi if [ "$MI" == "0" ]; then graphFan -1m month fi if [ "$HR" == "0" ]; then graphFan -1y year fi
MRTG에서 RRD파일을 생성하도록 설정했다면 MRTG에서 자동으로 RRD파일을 생성하고, 갱신하게 된다. 인터페이스의 모니터링 항목 한개당 94616 바이트의 작은 rrd 파일이 생성되며, 이 파일에 1년치 평균 데이터까지 모두 저장되어있다.
구분 | 저장 단위 시간 | |||
---|---|---|---|---|
5분 | 30분 | 2시간 | 1일 | |
저장 회수 | 600 | 700 | 775 | 796 |
총 저장 기간 | 2일 | 14일 | 64일 | 2년 |
그래프 | 2일 | 1주일 | 1개월 | 1년 |
아래는 MRTG에서 RRDtool 을 사용하도록 하는 경우, 자동으로 변환되는 .rrd
파일의 구조이다.
windy@wl ~ $ rrdtool info localhost_2.rrd filename = "localhost_2.rrd" rrd_version = "0003" step = 300 last_update = 1395623401 header_size = 2760 ds[ds0].index = 0 ds[ds0].type = "COUNTER" ds[ds0].minimal_heartbeat = 600 ds[ds0].min = 0.0000000000e+00 ds[ds0].max = 1.2500000000e+08 ds[ds0].last_ds = "547836283" ds[ds0].value = 0.0000000000e+00 ds[ds0].unknown_sec = 0 ds[ds1].index = 1 ds[ds1].type = "COUNTER" ds[ds1].minimal_heartbeat = 600 ds[ds1].min = 0.0000000000e+00 ds[ds1].max = 1.2500000000e+08 ds[ds1].last_ds = "3207582535" ds[ds1].value = 0.0000000000e+00 ds[ds1].unknown_sec = 0 rra[0].cf = "AVERAGE" rra[0].rows = 599 rra[0].cur_row = 1 rra[0].pdp_per_row = 1 rra[0].xff = 5.0000000000e-01 rra[0].cdp_prep[0].value = 9.9667774086e-01 rra[0].cdp_prep[0].unknown_datapoints = 0 rra[0].cdp_prep[1].value = 0.0000000000e+00 rra[0].cdp_prep[1].unknown_datapoints = 0 rra[1].cf = "AVERAGE" rra[1].rows = 700 rra[1].cur_row = 0 rra[1].pdp_per_row = 6 rra[1].xff = 5.0000000000e-01 rra[1].cdp_prep[0].value = 2.8752777778e+01 rra[1].cdp_prep[0].unknown_datapoints = 0 rra[1].cdp_prep[1].value = 1.7576666667e+01 rra[1].cdp_prep[1].unknown_datapoints = 0 rra[2].cf = "AVERAGE" rra[2].rows = 775 rra[2].cur_row = 0 rra[2].pdp_per_row = 24 rra[2].xff = 5.0000000000e-01 rra[2].cdp_prep[0].value = 2.8669861111e+01 rra[2].cdp_prep[0].unknown_datapoints = 0 rra[2].cdp_prep[1].value = 1.7910000000e+01 rra[2].cdp_prep[1].unknown_datapoints = 0 rra[3].cf = "AVERAGE" rra[3].rows = 796 rra[3].cur_row = 0 rra[3].pdp_per_row = 288 rra[3].xff = 5.0000000000e-01 rra[3].cdp_prep[0].value = 2.8746377315e+01 rra[3].cdp_prep[0].unknown_datapoints = 0 rra[3].cdp_prep[1].value = 1.7604444444e+01 rra[3].cdp_prep[1].unknown_datapoints = 0 rra[4].cf = "MAX" rra[4].rows = 600 rra[4].cur_row = 1 rra[4].pdp_per_row = 1 rra[4].xff = 5.0000000000e-01 rra[4].cdp_prep[0].value = 1.0000000000e+00 rra[4].cdp_prep[0].unknown_datapoints = 0 rra[4].cdp_prep[1].value = 0.0000000000e+00 rra[4].cdp_prep[1].unknown_datapoints = 0 rra[5].cf = "MAX" rra[5].rows = 700 rra[5].cur_row = 0 rra[5].pdp_per_row = 6 rra[5].xff = 5.0000000000e-01 rra[5].cdp_prep[0].value = 2.7753333333e+01 rra[5].cdp_prep[0].unknown_datapoints = 0 rra[5].cdp_prep[1].value = 1.7576666667e+01 rra[5].cdp_prep[1].unknown_datapoints = 0 rra[6].cf = "MAX" rra[6].rows = 775 rra[6].cur_row = 0 rra[6].pdp_per_row = 24 rra[6].xff = 5.0000000000e-01 rra[6].cdp_prep[0].value = 2.7753333333e+01 rra[6].cdp_prep[0].unknown_datapoints = 0 rra[6].cdp_prep[1].value = 1.7576666667e+01 rra[6].cdp_prep[1].unknown_datapoints = 0 rra[7].cf = "MAX" rra[7].rows = 796 rra[7].cur_row = 0 rra[7].pdp_per_row = 288 rra[7].xff = 5.0000000000e-01 rra[7].cdp_prep[0].value = 2.7753333333e+01 rra[7].cdp_prep[0].unknown_datapoints = 0 rra[7].cdp_prep[1].value = 1.7576666667e+01 rra[7].cdp_prep[1].unknown_datapoints = 0
등록된 노트가 없습니다
RSS ATOM XHTML 5 CSS3 |
Copyright © 2004-2025 Jo HoSeok. All rights reserved. |