1// Copyright 2016-2020 The Libsacloud Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package sacloud 16 17import ( 18 "encoding/json" 19 "math" 20 "strings" 21 "time" 22) 23 24// MonitorValue アクティビティモニター 25type MonitorValue struct { 26 CPUTime *float64 `json:"CPU-TIME,omitempty"` // CPU時間 27 Write *float64 `json:",omitempty"` // ディスク書き込み 28 Read *float64 `json:",omitempty"` // ディスク読み取り 29 Receive *float64 `json:",omitempty"` // パケット受信 30 Send *float64 `json:",omitempty"` // パケット送信 31 In *float64 `json:",omitempty"` // パケット受信 32 Out *float64 `json:",omitempty"` // パケット送信 33 TotalMemorySize *float64 `json:"Total-Memory-Size,omitempty"` // 総メモリサイズ 34 UsedMemorySize *float64 `json:"Used-Memory-Size,omitempty"` // 使用済みメモリサイズ 35 TotalDisk1Size *float64 `json:"Total-Disk1-Size,omitempty"` // 総ディスクサイズ 36 UsedDisk1Size *float64 `json:"Used-Disk1-Size,omitempty"` // 使用済みディスクサイズ 37 TotalDisk2Size *float64 `json:"Total-Disk2-Size,omitempty"` // 総ディスクサイズ 38 UsedDisk2Size *float64 `json:"Used-Disk2-Size,omitempty"` // 使用済みディスクサイズ 39 BinlogUsedSizeKiB *float64 `json:"binlogUsedSizeKiB,omitempty"` // バイナリログのサイズ(レプリケーション有効時のみ、master/slave両方で利用可能) 40 DelayTimeSec *float64 `json:"delayTimeSec,omitempty"` // レプリケーション遅延時間(レプリケーション有効時のみ、slave側のみ) 41 FreeDiskSize *float64 `json:"Free-Disk-Size,omitempty"` // 空きディスクサイズ(NFS) 42 ResponseTimeSec *float64 `json:"responsetimesec,omitempty"` // レスポンスタイム(シンプル監視) 43 UplinkBPS *float64 `json:"UplinkBps,omitempty"` // 上り方向トラフィック 44 DownlinkBPS *float64 `json:"DownlinkBps,omitempty"` // 下り方向トラフィック 45 ActiveConnections *float64 `json:"activeConnections,omitempty"` // アクティブコネクション(プロキシLB) 46 ConnectionsPerSec *float64 `json:"connectionsPerSec,omitempty"` // 秒間コネクション数 47} 48 49// UnmarshalJSON JSONアンマーシャル(配列、オブジェクトが混在するためここで対応) 50func (m *MonitorValue) UnmarshalJSON(data []byte) error { 51 targetData := strings.Replace(strings.Replace(string(data), " ", "", -1), "\n", "", -1) 52 if targetData == `[]` { 53 return nil 54 } 55 56 tmp := &struct { 57 CPUTime *float64 `json:"CPU-TIME,omitempty"` 58 Write *float64 `json:",omitempty"` 59 Read *float64 `json:",omitempty"` 60 Receive *float64 `json:",omitempty"` 61 Send *float64 `json:",omitempty"` 62 In *float64 `json:",omitempty"` 63 Out *float64 `json:",omitempty"` 64 TotalMemorySize *float64 `json:"Total-Memory-Size,omitempty"` 65 UsedMemorySize *float64 `json:"Used-Memory-Size,omitempty"` 66 TotalDisk1Size *float64 `json:"Total-Disk1-Size,omitempty"` 67 UsedDisk1Size *float64 `json:"Used-Disk1-Size,omitempty"` 68 TotalDisk2Size *float64 `json:"Total-Disk2-Size,omitempty"` 69 UsedDisk2Size *float64 `json:"Used-Disk2-Size,omitempty"` 70 BinlogUsedSizeKiB *float64 `json:"binlogUsedSizeKiB,omitempty"` 71 DelayTimeSec *float64 `json:"delayTimeSec,omitempty"` 72 FreeDiskSize *float64 `json:"Free-Disk-Size,omitempty"` 73 ResponseTimeSec *float64 `json:"responsetimesec,omitempty"` 74 UplinkBPS *float64 `json:"UplinkBps,omitempty"` 75 DownlinkBPS *float64 `json:"DownlinkBps,omitempty"` 76 ActiveConnections *float64 `json:"activeConnections,omitempty"` 77 ConnectionsPerSec *float64 `json:"connectionsPerSec,omitempty"` 78 }{} 79 if err := json.Unmarshal(data, &tmp); err != nil { 80 return err 81 } 82 83 m.CPUTime = tmp.CPUTime 84 m.Write = tmp.Write 85 m.Read = tmp.Read 86 m.Receive = tmp.Receive 87 m.Send = tmp.Send 88 m.In = tmp.In 89 m.Out = tmp.Out 90 m.TotalMemorySize = tmp.TotalMemorySize 91 m.UsedMemorySize = tmp.UsedMemorySize 92 m.TotalDisk1Size = tmp.TotalDisk1Size 93 m.UsedDisk1Size = tmp.UsedDisk1Size 94 m.TotalDisk2Size = tmp.TotalDisk2Size 95 m.UsedDisk2Size = tmp.UsedDisk2Size 96 m.BinlogUsedSizeKiB = tmp.BinlogUsedSizeKiB 97 m.DelayTimeSec = tmp.DelayTimeSec 98 m.FreeDiskSize = tmp.FreeDiskSize 99 m.ResponseTimeSec = tmp.ResponseTimeSec 100 m.UplinkBPS = tmp.UplinkBPS 101 m.DownlinkBPS = tmp.DownlinkBPS 102 m.ActiveConnections = tmp.ActiveConnections 103 m.ConnectionsPerSec = tmp.ConnectionsPerSec 104 105 return nil 106} 107 108// ResourceMonitorRequest アクティビティモニター取得リクエスト 109type ResourceMonitorRequest struct { 110 Start *time.Time `json:",omitempty"` // 取得開始時間 111 End *time.Time `json:",omitempty"` // 取得終了時間 112} 113 114// NewResourceMonitorRequest アクティビティモニター取得リクエスト作成 115func NewResourceMonitorRequest(start *time.Time, end *time.Time) *ResourceMonitorRequest { 116 res := &ResourceMonitorRequest{} 117 if start != nil { 118 t := start.Truncate(time.Second) 119 res.Start = &t 120 } 121 if end != nil { 122 t := end.Truncate(time.Second) 123 res.End = &t 124 } 125 return res 126} 127 128// ResourceMonitorResponse アクティビティモニターレスポンス 129type ResourceMonitorResponse struct { 130 Data *MonitorValues `json:",omitempty"` // メトリクス 131} 132 133// UnmarshalJSON JSONアンマーシャル(配列、オブジェクトが混在するためここで対応) 134func (m *MonitorValues) UnmarshalJSON(data []byte) error { 135 targetData := strings.Replace(strings.Replace(string(data), " ", "", -1), "\n", "", -1) 136 if targetData == `[]` { 137 return nil 138 } 139 140 tmp := map[string]*MonitorValue{} 141 if err := json.Unmarshal(data, &tmp); err != nil { 142 return err 143 } 144 145 value := MonitorValues(tmp) 146 *m = value 147 return nil 148} 149 150// MonitorSummaryData メトリクスサマリー 151type MonitorSummaryData struct { 152 Max float64 // 最大値 153 Min float64 // 最小値 154 Avg float64 // 平均値 155 Count float64 // データ個数 156 157} 158 159// MonitorSummary アクティビティーモニター サマリー 160type MonitorSummary struct { 161 CPU *MonitorSummaryData // CPU時間サマリー 162 Disk *struct { // ディスク利用サマリー 163 Write *MonitorSummaryData // ディスク書き込みサマリー 164 Read *MonitorSummaryData // ディスク読み取りサマリー 165 } 166 Interface *struct { // NIC送受信サマリー 167 Receive *MonitorSummaryData // 受信パケットサマリー 168 Send *MonitorSummaryData // 送信パケットサマリー 169 } 170} 171 172// MonitorValues メトリクス リスト 173type MonitorValues map[string]*MonitorValue 174 175// FlatMonitorValue フラット化したメトリクス 176type FlatMonitorValue struct { 177 Time time.Time // 対象時刻 178 Value float64 // 値 179} 180 181// Calc サマリー計算 182func (m *MonitorValues) Calc() *MonitorSummary { 183 184 res := &MonitorSummary{} 185 res.CPU = m.calcBy(func(v *MonitorValue) *float64 { return v.CPUTime }) 186 res.Disk = &struct { 187 Write *MonitorSummaryData 188 Read *MonitorSummaryData 189 }{ 190 Write: m.calcBy(func(v *MonitorValue) *float64 { return v.Write }), 191 Read: m.calcBy(func(v *MonitorValue) *float64 { return v.Read }), 192 } 193 res.Interface = &struct { 194 Receive *MonitorSummaryData 195 Send *MonitorSummaryData 196 }{ 197 Receive: m.calcBy(func(v *MonitorValue) *float64 { return v.Receive }), 198 Send: m.calcBy(func(v *MonitorValue) *float64 { return v.Send }), 199 } 200 201 return res 202} 203 204func (m *MonitorValues) calcBy(f func(m *MonitorValue) *float64) *MonitorSummaryData { 205 res := &MonitorSummaryData{} 206 var sum float64 207 for _, data := range map[string]*MonitorValue(*m) { 208 value := f(data) 209 if value != nil { 210 res.Count++ 211 res.Min = math.Min(res.Min, *value) 212 res.Max = math.Max(res.Max, *value) 213 sum += *value 214 } 215 } 216 if sum > 0 && res.Count > 0 { 217 res.Avg = sum / res.Count 218 } 219 220 return res 221} 222 223// FlattenCPUTimeValue フラット化 CPU時間 224func (m *MonitorValues) FlattenCPUTimeValue() ([]FlatMonitorValue, error) { 225 return m.flattenValue(func(v *MonitorValue) *float64 { return v.CPUTime }) 226} 227 228// FlattenDiskWriteValue フラット化 ディスク書き込み 229func (m *MonitorValues) FlattenDiskWriteValue() ([]FlatMonitorValue, error) { 230 return m.flattenValue(func(v *MonitorValue) *float64 { return v.Write }) 231} 232 233// FlattenDiskReadValue フラット化 ディスク読み取り 234func (m *MonitorValues) FlattenDiskReadValue() ([]FlatMonitorValue, error) { 235 return m.flattenValue(func(v *MonitorValue) *float64 { return v.Read }) 236} 237 238// FlattenPacketSendValue フラット化 パケット送信 239func (m *MonitorValues) FlattenPacketSendValue() ([]FlatMonitorValue, error) { 240 return m.flattenValue(func(v *MonitorValue) *float64 { return v.Send }) 241} 242 243// FlattenPacketReceiveValue フラット化 パケット受信 244func (m *MonitorValues) FlattenPacketReceiveValue() ([]FlatMonitorValue, error) { 245 return m.flattenValue(func(v *MonitorValue) *float64 { return v.Receive }) 246} 247 248// FlattenInternetInValue フラット化 パケット受信 249func (m *MonitorValues) FlattenInternetInValue() ([]FlatMonitorValue, error) { 250 return m.flattenValue(func(v *MonitorValue) *float64 { return v.In }) 251} 252 253// FlattenInternetOutValue フラット化 パケット送信 254func (m *MonitorValues) FlattenInternetOutValue() ([]FlatMonitorValue, error) { 255 return m.flattenValue(func(v *MonitorValue) *float64 { return v.Out }) 256} 257 258// FlattenTotalMemorySizeValue フラット化 総メモリサイズ 259func (m *MonitorValues) FlattenTotalMemorySizeValue() ([]FlatMonitorValue, error) { 260 return m.flattenValue(func(v *MonitorValue) *float64 { return v.TotalMemorySize }) 261} 262 263// FlattenUsedMemorySizeValue フラット化 使用済みメモリサイズ 264func (m *MonitorValues) FlattenUsedMemorySizeValue() ([]FlatMonitorValue, error) { 265 return m.flattenValue(func(v *MonitorValue) *float64 { return v.UsedMemorySize }) 266} 267 268// FlattenTotalDisk1SizeValue フラット化 総ディスクサイズ 269func (m *MonitorValues) FlattenTotalDisk1SizeValue() ([]FlatMonitorValue, error) { 270 return m.flattenValue(func(v *MonitorValue) *float64 { return v.TotalDisk1Size }) 271} 272 273// FlattenUsedDisk1SizeValue フラット化 使用済みディスクサイズ 274func (m *MonitorValues) FlattenUsedDisk1SizeValue() ([]FlatMonitorValue, error) { 275 return m.flattenValue(func(v *MonitorValue) *float64 { return v.UsedDisk1Size }) 276} 277 278// FlattenTotalDisk2SizeValue フラット化 総ディスクサイズ 279func (m *MonitorValues) FlattenTotalDisk2SizeValue() ([]FlatMonitorValue, error) { 280 return m.flattenValue(func(v *MonitorValue) *float64 { return v.TotalDisk2Size }) 281} 282 283// FlattenUsedDisk2SizeValue フラット化 使用済みディスクサイズ 284func (m *MonitorValues) FlattenUsedDisk2SizeValue() ([]FlatMonitorValue, error) { 285 return m.flattenValue(func(v *MonitorValue) *float64 { return v.UsedDisk2Size }) 286} 287 288// FlattenBinlogUsedSizeKiBValue フラット化 バイナリログサイズ 289func (m *MonitorValues) FlattenBinlogUsedSizeKiBValue() ([]FlatMonitorValue, error) { 290 return m.flattenValue(func(v *MonitorValue) *float64 { return v.BinlogUsedSizeKiB }) 291} 292 293// FlattenDelayTimeSecValue フラット化 レプリケーション遅延時間 294func (m *MonitorValues) FlattenDelayTimeSecValue() ([]FlatMonitorValue, error) { 295 return m.flattenValue(func(v *MonitorValue) *float64 { return v.DelayTimeSec }) 296} 297 298// FlattenFreeDiskSizeValue フラット化 空きディスクサイズ(NFS) 299func (m *MonitorValues) FlattenFreeDiskSizeValue() ([]FlatMonitorValue, error) { 300 return m.flattenValue(func(v *MonitorValue) *float64 { return v.FreeDiskSize }) 301} 302 303// FlattenResponseTimeSecValue フラット化 レスポンスタイム(シンプル監視) 304func (m *MonitorValues) FlattenResponseTimeSecValue() ([]FlatMonitorValue, error) { 305 return m.flattenValue(func(v *MonitorValue) *float64 { return v.ResponseTimeSec }) 306} 307 308// FlattenUplinkBPSValue フラット化 上り方向トラフィック(セキュアモバイルSIM) 309func (m *MonitorValues) FlattenUplinkBPSValue() ([]FlatMonitorValue, error) { 310 return m.flattenValue(func(v *MonitorValue) *float64 { return v.UplinkBPS }) 311} 312 313// FlattenDownlinkBPSValue フラット化 下り方向トライフィック(セキュアモバイルSIM) 314func (m *MonitorValues) FlattenDownlinkBPSValue() ([]FlatMonitorValue, error) { 315 return m.flattenValue(func(v *MonitorValue) *float64 { return v.DownlinkBPS }) 316} 317 318// FlattenActiveConnections フラット化 アクティブコネクション 319func (m *MonitorValues) FlattenActiveConnections() ([]FlatMonitorValue, error) { 320 return m.flattenValue(func(v *MonitorValue) *float64 { return v.ActiveConnections }) 321} 322 323// FlattenConnectionsPerSec フラット化 秒間接続数 324func (m *MonitorValues) FlattenConnectionsPerSec() ([]FlatMonitorValue, error) { 325 return m.flattenValue(func(v *MonitorValue) *float64 { return v.ConnectionsPerSec }) 326} 327 328func (m *MonitorValues) flattenValue(f func(*MonitorValue) *float64) ([]FlatMonitorValue, error) { 329 var res []FlatMonitorValue 330 331 for k, v := range map[string]*MonitorValue(*m) { 332 if f(v) == nil { 333 continue 334 } 335 time, err := time.Parse(time.RFC3339, k) // RFC3339 ≒ ISO8601 336 if err != nil { 337 return res, err 338 } 339 res = append(res, FlatMonitorValue{ 340 // Time 341 Time: time, 342 // Value 343 Value: *f(v), 344 }) 345 } 346 return res, nil 347} 348 349// HasValue 取得したアクティビティーモニターに有効値が含まれるか判定 350func (m *MonitorValue) HasValue() bool { 351 values := []*float64{ 352 m.CPUTime, 353 m.Read, m.Receive, 354 m.Send, m.Write, 355 m.In, m.Out, 356 m.TotalMemorySize, m.UsedMemorySize, 357 m.TotalDisk1Size, m.UsedDisk1Size, 358 m.TotalDisk2Size, m.UsedDisk2Size, 359 m.BinlogUsedSizeKiB, m.DelayTimeSec, 360 m.FreeDiskSize, m.ResponseTimeSec, 361 m.UplinkBPS, m.DownlinkBPS, 362 m.ActiveConnections, m.ConnectionsPerSec, 363 } 364 for _, v := range values { 365 if v != nil { 366 return true 367 } 368 } 369 return false 370} 371