github.com/simpleiot/simpleiot@v0.18.3/frontend/src/Components/NodeMetrics.elm (about) 1 module Components.NodeMetrics exposing (view) 2 3 import Api.Point as Point 4 import Components.NodeOptions exposing (NodeOptions, oToInputO) 5 import Dict exposing (Dict) 6 import Element exposing (..) 7 import Element.Border as Border 8 import Element.Font as Font 9 import FormatNumber exposing (format) 10 import FormatNumber.Locales exposing (Decimals(..), usLocale) 11 import Round 12 import Time 13 import UI.Icon as Icon 14 import UI.NodeInputs as NodeInputs 15 import UI.Style exposing (colors) 16 import UI.ViewIf exposing (viewIf) 17 import Utils.Iso8601 exposing (toDateTimeString) 18 19 20 view : NodeOptions msg -> Element msg 21 view o = 22 column 23 [ width fill 24 , Border.widthEach { top = 2, bottom = 0, left = 0, right = 0 } 25 , Border.color colors.black 26 , spacing 6 27 ] 28 <| 29 wrappedRow [ spacing 10 ] 30 [ Icon.barChart 31 , text <| 32 Point.getText o.node.points Point.typeDescription "" 33 ] 34 :: (if o.expDetail then 35 let 36 opts = 37 oToInputO o 100 38 39 textInput = 40 NodeInputs.nodeTextInput opts "0" 41 42 optionInput = 43 NodeInputs.nodeOptionInput opts "0" 44 45 numberInput = 46 NodeInputs.nodeNumberInput opts "0" 47 48 metricsType = 49 Point.getText o.node.points Point.typeType "" 50 in 51 [ textInput Point.typeDescription "Description" "" 52 , optionInput Point.typeType 53 "Type" 54 [ ( Point.valueSystem, "system" ) 55 , ( Point.valueApp, "this application" ) 56 , ( Point.valueProcess, "named process" ) 57 58 -- modern systems have so many processes (1000's) 59 -- and we need to better be able to handle this point 60 -- load for repeated points, so disable this for now 61 -- , ( Point.valueAllProcesses, "all processes" ) 62 ] 63 , viewIf (metricsType == Point.valueProcess) <| 64 textInput Point.typeName "proc name" "" 65 , numberInput Point.typePeriod "Period (s)" 66 , NodeInputs.nodeKeyValueInput opts Point.typeTag "Tags" "Add Tag" 67 , viewMetrics o.zone <| Point.filterSpecialPoints <| List.sortWith Point.sort o.node.points 68 ] 69 70 else 71 [] 72 ) 73 74 75 viewMetrics : Time.Zone -> List Point.Point -> Element msg 76 viewMetrics z ios = 77 let 78 formaters = 79 metricFormaters z 80 81 fm = 82 formatMetric formaters 83 in 84 table [ padding 7 ] 85 { data = List.map fm ios 86 , columns = 87 let 88 cell = 89 el [ paddingXY 15 5, Border.width 1 ] 90 in 91 [ { header = cell <| el [ Font.bold, centerX ] <| text "Metric" 92 , width = fill 93 , view = \m -> cell <| text m.desc 94 } 95 , { header = cell <| el [ Font.bold, centerX ] <| text "Value" 96 , width = fill 97 , view = \m -> cell <| el [ alignRight ] <| text m.value 98 } 99 ] 100 } 101 102 103 formatMetric : Dict String MetricFormat -> Point.Point -> { desc : String, value : String } 104 formatMetric formaters p = 105 case Dict.get p.typ formaters of 106 Just f -> 107 { desc = f.desc p, value = f.vf p } 108 109 Nothing -> 110 Point.renderPoint2 p 111 112 113 type alias MetricFormat = 114 { desc : Point.Point -> String 115 , vf : Point.Point -> String 116 } 117 118 119 metricFormaters : Time.Zone -> Dict String MetricFormat 120 metricFormaters z = 121 let 122 toTimeWithZone = 123 toTime z 124 in 125 Dict.fromList 126 [ ( "metricAppAlloc", { desc = descS "App Memory Alloc", vf = toMiB } ) 127 , ( "metricAppNumGoroutine", { desc = descS "App Goroutine Count", vf = toWhole } ) 128 , ( "metricProcCPUPercent", { desc = descKey "Proc CPU %", vf = toPercent } ) 129 , ( "metricProcMemPercent", { desc = descKey "Proc Mem %", vf = toPercent } ) 130 , ( "metricProcMemRSS", { desc = descKey "Proc Mem RSS", vf = toMiB } ) 131 , ( "count", { desc = descKey "Proc Count", vf = toWhole } ) 132 , ( "host", { desc = descKey "Host", vf = toText } ) 133 , ( "hostBootTime", { desc = descS "Host Boot Time", vf = toTimeWithZone } ) 134 , ( "metricSysCPUPercent", { desc = descS "Sys CPU %", vf = toPercent } ) 135 , ( "metricSysDiskUsedPercent", { desc = descKey "Disk Used %", vf = toPercent } ) 136 , ( "metricSysLoad", { desc = descKey "Load", vf = \p -> Round.round 2 p.value } ) 137 , ( "metricSysMemUsedPercent", { desc = descS "Memory used %", vf = toPercent } ) 138 , ( "metricSysMem", { desc = descKey "Memory", vf = toMiB } ) 139 , ( "metricSysNetBytesRecv", { desc = descKey "Net RX", vf = toWhole } ) 140 , ( "metricSysNetBytesSent", { desc = descKey "Net TX", vf = toWhole } ) 141 , ( "metricSysUptime", { desc = descKey "Uptime", vf = toWhole } ) 142 , ( "temp", { desc = descKey "Temp", vf = \p -> Round.round 1 p.value } ) 143 ] 144 145 146 toMiB : Point.Point -> String 147 toMiB p = 148 format { usLocale | decimals = Exact 1 } (p.value / (1024 * 1024)) 149 150 151 toPercent : Point.Point -> String 152 toPercent p = 153 Round.round 1 p.value ++ " %" 154 155 156 toWhole : Point.Point -> String 157 toWhole p = 158 format { usLocale | decimals = Exact 0 } p.value 159 160 161 toText : Point.Point -> String 162 toText p = 163 if p.text == "" then 164 " " 165 166 else 167 p.text 168 169 170 toTime : Time.Zone -> Point.Point -> String 171 toTime z p = 172 let 173 t = 174 Time.millisToPosix (round p.value * 1000) 175 in 176 toDateTimeString z t 177 178 179 descS : String -> Point.Point -> String 180 descS d _ = 181 d 182 183 184 descKey : String -> Point.Point -> String 185 descKey d p = 186 d ++ " " ++ p.key