CDEFTUTORIAL(1) rrdtool CDEFTUTORIAL(1) (NAME) cdeftutorial - CDEF Alex van den Bogaerdt (DESCRIPTION) : CDEF RRDtool. . . ! . -- Alex van den Bogaerdt (Why this tutorial?) RRDtool . RRDtool . ( ) . RRDtool : . . . (More reading) rpntutorial Steve Rader . . CDEF (What are CDEFs?) RRD "DEF" . ( x ). . CDEF : DEF . (SYNTAX) DEF:var_name_1=some.rrd:ds_name:CF CDEF:var_name_2=RPN_expression "var_name_1" "ds_name" RRD "some.rrd" "CF" . SNMP ifInOctets mrtg.rrd DS "in" . DEF : DEF:inbytes=mrtg.rrd:in:AVERAGE ( ). ( "CDEF") "inbytes" (inbits) : CDEF:inbits=inbytes,8,* RRDtool inbytes inbits . . inbits inbytes . CDEF ( inbits) DEF ( inbytes) !.SH " RPN (RPN- expressions)" RPN << >> (Reverse Polish Notation) : (stack) . ( ) . . : . RRDtool ( ). : 1. 2. inbytes 3. 4. 5. 6. inbits . inbytes 10 : 1. || 2. |10| 3. |10|8| 4. |10|8|*| 5. |80| 6. || ( ) ( ). . ( 80). . : y = A - B --> y=minus(A,B) --> CDEF:y=A,B,- ( ). f(A,B) "f" . RPN (Converting your wishes to RPN) . . RPN . RRD . WAN . : router1.rrd with link1in link2in router2.rrd with link1in link2in router3.rrd with link1in link2in link2in router2.rrd. : ( "router1.rrd:link1in" DS link1in router1.rrd ) router1.rrd:link1in router1.rrd:link2in router2.rrd:link1in router3.rrd:link1in router3.rrd:link2in -------------------- + (outcome of the sum) : "add(router1.rrd:link1in , router1.rrd:link2in , router2.rrd:link1in , router3.rrd:link1in , router3.rrd:link2.in)" RRDtool RPN : DEF:a=router1.rrd:link1in:AVERAGE DEF:b=router1.rrd:link2in:AVERAGE DEF:c=router2.rrd:link1in:AVERAGE DEF:d=router3.rrd:link1in:AVERAGE DEF:e=router3.rrd:link2in:AVERAGE : "add(a,b,c,d,e)" RPN . a b c d e . push a: a stack contains the value of a push b and add: b,+ stack contains the result of a+b push c and add: c,+ stack contains the result of a+b+c push d and add: d,+ stack contains the result of a+b+c+d push e and add: e,+ stack contains the result of a+b+c+d+e : ( ( ( (a+b) + c) + d) + e) > RPN : "CDEF:result=a,b,+,c,+,d,+,e,+" . a b c b c a . RPN "CDEF:result=a,b,c,d,e,+,+,+,+" : push value of variable a on the stack: a push value of variable b on the stack: a b push value of variable c on the stack: a b c push value of variable d on the stack: a b c d push value of variable e on the stack: a b c d e push operator + on the stack: a b c d e + and process it: a b c P (where P == d+e) push operator + on the stack: a b c P + and process it: a b Q (where Q == c+P) push operator + on the stack: a b Q + and process it: a R (where R == b+Q) push operator + on the stack: a R + and process it: S (where S == a+R) RPN "a,b,c,d,e,+,+,+,+" "((((d+e)+c)+b)+a)" "a,b,+,c,+,d,+,e,+" . << >> . : : "let result = a+b*c". a . b c a b . RPN . : << b*c a >> RPN : "result=a,b,c,*,+" : "result=b,c,*,a,+" "a*(b+c)" RPN . b c a . RPN : "result=a,b,c,+,*". . RPN RRDtool . RRDtool . ..SH " (Some special numbers)" (The unknown value) . (busy links) . RRDtool ( ) . . PDP primary data point ( ) . RRD RRA CDP ( consolidated data point) PDP . PDP (unknown) : 1. . "heartbeat" . 2. ( template) "U" . CDP CDP . PDP CDP . xff . PDP ! PDP CDP CDP ! : counter value resulting rate 10'000 10'060 1; (10'060-10'000)/60 == 1 10'120 1; (10'120-10'060)/60 == 1 unknown unknown; you don't know the last value 10'240 unknown; you don't know the previous value 10'300 1; (10'300-10'240)/60 == 1 CDP PDP PDP . xff 0.5 ( ) CDP 1 . xff 0.2 CDP . heartbeat PDP CDP xff . RRA . (Working with unknown data in your database) RRA . . "result=a,b,+" a b . <> <<>> . . RRD . ... ( ) ( ) . CDEF . ( !) ( : ). . (Infinity) . . . RRDtool ( ) ( ) () (- !-). RRDtool AREA . AREA . . . (Working with unknown data and infinity) ( ) ( ). CDEF . . (Some examples) : RRD (Example: using a recently created RRD) . (throughput) . router.rrd router2.rrd ( router.rrd) ( router2.rrd) . : o . . o CDEF . . . . : : << >>. : if (value is unknown) then (zero) else (value). rrdgraph "UN" . "IF" . "IF" . "true" . "UN" CDEF . "IF" : if true return a if false return b RPN: "result=x,a,b,IF" "x" true false. "x" "(value is unknown)" RPN : "result=value,UN" : "result=value,UN,a,b,IF" "a" "b" : "CDEF:result=value,UN,0,value,IF" RPN (Steve Rader) . RPN RRDtool : For any known value, the expression evaluates as follows: CDEF:result=value,UN,0,value,IF (value,UN) is not true so it becomes 0 CDEF:result=0,0,value,IF "IF" will return the 3rd value CDEF:result=value The known value is returned For the unknown value, this happens: CDEF:result=value,UN,0,value,IF (value,UN) is true so it becomes 1 CDEF:result=1,0,value,IF "IF" sees 1 and returns the 2nd value CDEF:result=0 Zero is returned . RRD ..SS ": " . . : o . o xxx . o xxx . : . 00:35:57 MET DST . 1970-01-01 937'521'357 . <<>> ( ). 00:35:57 MET DST 937'521'357 gnu date : date -d "19990917 00:35:57" +%s (dump) . . . : 1. (timestamp) 937'521'357 . 2. . 3. . : if (true) return the original value : if (true) return "a" if (false) return "b" (true) (false) . . "TIME" . "GT" . "GT" "IF" . "if (time > 937521357) then (return a) else (return b)" . : if (x) then a else b where x represents "time>937521357" where a represents the original value where b represents the outcome of the previous example time>937521357 --> TIME,937521357,GT if (x) then a else b --> x,a,b,IF substitute x --> TIME,937521357,GT,a,b,IF substitute a --> TIME,937521357,GT,value,b,IF substitute b --> TIME,937521357,GT,value,value,UN,0,value,IF,IF : "CDEF:result=TIME,937521357,GT,value,value,UN,0,value,IF,IF" . : (spikes) . . 10mb/s 100kb/s . : 1. 100kb/s ( ). 2. 100kb/s . : if (number > 100) then unknown else number : if (number > 100) then 100 else number. <<>> rigid RRDtool graph . (autoscaling) . 100kb/s . "IF" "GT" . "if (x) then (y) else (z)" "CDEF:result=x,y,z,IF" x y z . x << 100kb/s>> "number,100000,GT" ( 1'000 b/s !). "z" "number" "y" "UNKN" "100000" 100kb/s. CDEF : CDEF:result=number,100000,GT,UNKN,number,IF CDEF:result=number,100000,GT,100000,number,IF <<>> . :) (time stamp) . : TIME,begintime,GE TIME,endtime,LE CDEF 0 false () 1 true () . IF 0 ( 1) (Wataru Satoh) <<*>> <<+>> AND OR . <<*>> (false) . <<+>> false (0) false (0) . : ** 0 <> . <<-1,1,+>> ( <> ) FALSE ... <<+>> ( ) . CDEF : DEF:ds0=router1.rrd:AVERAGE CDEF:ds0modified=TIME,begintime,GT,TIME,endtime,LE,*,ds0,UNKN,IF true ds0 . : DEF:ds0=router1.rrd:AVERAGE CDEF:ds0modified=TIME,begintime,LT,TIME,endtime,GT,+,UNKN,ds0,IF true UNKNOWN . : (unknown) (terminal server) . ( ) <> (<< >> Not a Number) NaN Unknown . . : DEF:users1=location1.rrd:onlineTS1:LAST DEF:users2=location1.rrd:onlineTS2:LAST DEF:users3=location2.rrd:onlineTS1:LAST DEF:users4=location2.rrd:onlineTS2:LAST CDEF:allusers=users1,users2,users3,users4,+,+,+ allusers users1..users4 . . CDEF unknown (INF) : CDEF:wrongdata=allusers,UN,INF,UNKN,IF <> true false (x) <> allusers (unknown) . (y) <> <> ( ) (z) <> . : if (allusers == unknown) then return INF else return UNKN. AREA <> . ( allusers ) AREA . INF ( allusers ) AREA . AREA:allusers#0000FF:combined user count AREA:wrongdata#FF0000:unknown data (STACKed): stack ( ) . . users3 : users1 users2 users1 users3 users4 users2 . CDEF <<>> : DEF:users1=location1.rrd:onlineTS1:LAST DEF:users2=location1.rrd:onlineTS2:LAST DEF:users3=location2.rrd:onlineTS1:LAST DEF:users4=location2.rrd:onlineTS2:LAST CDEF:allusers=users1,users2,users3,users4,+,+,+ CDEF:wrongdata=allusers,UN,INF,UNKN,IF AREA:users1#0000FF:users at ts1 STACK:users2#00FF00:users at ts2 STACK:users3#00FFFF:users at ts3 STACK:users4#FFFF00:users at ts4 AREA:wrongdata#FF0000:unknown data users1..users4 AREA <> X STACKed . CDEF ( <> ). CDEF : o . o GPRINT . CDEF <> : CDEF:wrongdata=users1,users2,users3,users4,+,+,+,UN,INF,UNKN,IF GPRINT : COMMENT:"Total number of users seen" GPRINT:allusers:MAX:"Maximum: %6.0lf" GPRINT:allusers:MIN:"Minimum: %6.0lf" GPRINT:allusers:AVERAGE:"Average: %6.0lf" GPRINT:allusers:LAST:"Current: %6.0lf\n" (Degrees Celsius vs. Degrees Fahrenheit) : F=9/5*C+32 rrdtool graph demo.png --title="Demo Graph" \ DEF:cel=demo.rrd:exhaust:AVERAGE \ CDEF:far=9,5,/,cel,*,32,+ \ LINE2:cel#00a000:"D. Celsius" \ LINE2:far#ff0000:"D. Fahrenheit\c" DS <> <> <> . CDEF : CDEF:far=9,5,/,cel,*,32,+ 1. push 9, push 5 2. push function "divide" and process it the stack now contains 9/5 3. push variable "cel" 4. push function "multiply" and process it the stack now contains 9/5*cel 5. push 32 6. push function "plus" and process it the stack contains now the temperature in Fahrenheit (Changing unknown into zero) rrdtool graph demo.png --title="Demo Graph" \ DEF:idat1=interface1.rrd:ds0:AVERAGE \ DEF:idat2=interface2.rrd:ds0:AVERAGE \ DEF:odat1=interface1.rrd:ds1:AVERAGE \ DEF:odat2=interface2.rrd:ds1:AVERAGE \ CDEF:agginput=idat1,UN,0,idat1,IF,idat2,UN,0,idat2,IF,+,8,* \ CDEF:aggoutput=odat1,UN,0,odat1,IF,odat2,UN,0,odat2,IF,+,8,* \ AREA:agginput#00cc00:Input Aggregate \ LINE1:aggoutput#0000FF:Output Aggregate CDEF . . CDEF : idat1,UN --> a 0 --> b idat1 --> c if (a) then (b) else (c) <> <> <<0>> . <> . <> . <> . <> . <> <> <> . <> <> (unknown) . (bytes/s) (bits/s) . (Infinity demo) rrdtool graph example.png --title="INF demo" \ DEF:val1=some.rrd:ds0:AVERAGE \ DEF:val2=some.rrd:ds1:AVERAGE \ DEF:val3=some.rrd:ds2:AVERAGE \ DEF:val4=other.rrd:ds0:AVERAGE \ CDEF:background=val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF \ CDEF:wipeout=val1,val2,val3,val4,+,+,+,UN,INF,UNKN,IF \ AREA:background#F0F0F0 \ AREA:val1#0000FF:Value1 \ STACK:val2#00C000:Value2 \ STACK:val3#FFFF00:Value3 \ STACK:val4#FFC000:Value4 \ AREA:whipeout#FF0000:Unknown (INF) . CDEF <> . "val4,POP,TIME,7200,%,3600,LE,INF,UNKN,IF" RPN <> <> . . <