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