scraper.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // Copyright The OpenTelemetry Authors
  2. // SPDX-License-Identifier: Apache-2.0
  3. package bigipreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/bigipreceiver"
  4. import (
  5. "context"
  6. "errors"
  7. "fmt"
  8. "strings"
  9. "time"
  10. "go.opentelemetry.io/collector/component"
  11. "go.opentelemetry.io/collector/pdata/pcommon"
  12. "go.opentelemetry.io/collector/pdata/pmetric"
  13. "go.opentelemetry.io/collector/receiver"
  14. "go.opentelemetry.io/collector/receiver/scrapererror"
  15. "go.uber.org/zap"
  16. "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/bigipreceiver/internal/metadata"
  17. "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/bigipreceiver/internal/models"
  18. )
  19. // custom errors
  20. var (
  21. errClientNotInit = errors.New("client not initialized")
  22. errScrapedNoMetrics = errors.New("failed to scrape any metrics")
  23. )
  24. // bigipScraper handles scraping of Big-IP metrics
  25. type bigipScraper struct {
  26. client client
  27. logger *zap.Logger
  28. cfg *Config
  29. settings component.TelemetrySettings
  30. mb *metadata.MetricsBuilder
  31. }
  32. // newScraper creates an initialized bigipScraper
  33. func newScraper(logger *zap.Logger, cfg *Config, settings receiver.CreateSettings) *bigipScraper {
  34. return &bigipScraper{
  35. logger: logger,
  36. cfg: cfg,
  37. settings: settings.TelemetrySettings,
  38. mb: metadata.NewMetricsBuilder(cfg.MetricsBuilderConfig, settings),
  39. }
  40. }
  41. // start initializes a new big-ip client for the scraper
  42. func (s *bigipScraper) start(_ context.Context, host component.Host) (err error) {
  43. s.client, err = newClient(s.cfg, host, s.settings, s.logger)
  44. return
  45. }
  46. // scrape collects and creates OTEL metrics from a Big-IP environment
  47. func (s *bigipScraper) scrape(ctx context.Context) (pmetric.Metrics, error) {
  48. now := pcommon.NewTimestampFromTime(time.Now())
  49. // validate we don't attempt to scrape without initializing the client
  50. if s.client == nil {
  51. return pmetric.NewMetrics(), errClientNotInit
  52. }
  53. collectedMetrics := false
  54. // initialize auth token
  55. err := s.client.GetNewToken(ctx)
  56. if err != nil {
  57. return pmetric.NewMetrics(), err
  58. }
  59. var scrapeErrors scrapererror.ScrapeErrors
  60. // scrape metrics for virtual servers
  61. virtualServers, err := s.client.GetVirtualServers(ctx)
  62. if err != nil {
  63. scrapeErrors.AddPartial(1, err)
  64. s.logger.Warn("Failed to scrape virtual server metrics", zap.Error(err))
  65. } else {
  66. collectedMetrics = true
  67. for key := range virtualServers.Entries {
  68. virtualServerStats := virtualServers.Entries[key]
  69. s.collectVirtualServers(&virtualServerStats, now)
  70. }
  71. }
  72. // scrape metrics for pools
  73. pools, err := s.client.GetPools(ctx)
  74. if err != nil {
  75. scrapeErrors.AddPartial(1, err)
  76. s.logger.Warn("Failed to scrape pool metrics", zap.Error(err))
  77. } else {
  78. collectedMetrics = true
  79. for key := range pools.Entries {
  80. poolStats := pools.Entries[key]
  81. s.collectPools(&poolStats, now)
  82. }
  83. }
  84. // scrape metrics for pool members
  85. poolMembers, err := s.client.GetPoolMembers(ctx, pools)
  86. if errors.Is(err, errCollectedNoPoolMembers) {
  87. scrapeErrors.AddPartial(1, err)
  88. s.logger.Warn("Failed to scrape pool member metrics", zap.Error(err))
  89. } else {
  90. if err != nil {
  91. scrapeErrors.AddPartial(1, err)
  92. s.logger.Warn("Failed to scrape some pool member metrics", zap.Error(err))
  93. }
  94. collectedMetrics = true
  95. for key := range poolMembers.Entries {
  96. poolMemberStats := poolMembers.Entries[key]
  97. s.collectPoolMembers(&poolMemberStats, now)
  98. }
  99. }
  100. // scrape metrics for nodes
  101. nodes, err := s.client.GetNodes(ctx)
  102. if err != nil {
  103. scrapeErrors.AddPartial(1, err)
  104. s.logger.Warn("Failed to scrape node metrics", zap.Error(err))
  105. } else {
  106. collectedMetrics = true
  107. for key := range nodes.Entries {
  108. nodeStats := nodes.Entries[key]
  109. s.collectNodes(&nodeStats, now)
  110. }
  111. }
  112. if !collectedMetrics {
  113. return pmetric.NewMetrics(), errScrapedNoMetrics
  114. }
  115. return s.mb.Emit(), scrapeErrors.Combine()
  116. }
  117. // collectVirtualServers collects virtual server metrics
  118. func (s *bigipScraper) collectVirtualServers(virtualServerStats *models.VirtualServerStats, now pcommon.Timestamp) {
  119. s.mb.RecordBigipVirtualServerDataTransmittedDataPoint(now, virtualServerStats.NestedStats.Entries.ClientsideBitsIn.Value, metadata.AttributeDirectionReceived)
  120. s.mb.RecordBigipVirtualServerDataTransmittedDataPoint(now, virtualServerStats.NestedStats.Entries.ClientsideBitsOut.Value, metadata.AttributeDirectionSent)
  121. s.mb.RecordBigipVirtualServerConnectionCountDataPoint(now, virtualServerStats.NestedStats.Entries.ClientsideCurConns.Value)
  122. s.mb.RecordBigipVirtualServerPacketCountDataPoint(now, virtualServerStats.NestedStats.Entries.ClientsidePktsIn.Value, metadata.AttributeDirectionReceived)
  123. s.mb.RecordBigipVirtualServerPacketCountDataPoint(now, virtualServerStats.NestedStats.Entries.ClientsidePktsOut.Value, metadata.AttributeDirectionSent)
  124. s.mb.RecordBigipVirtualServerRequestCountDataPoint(now, virtualServerStats.NestedStats.Entries.TotalRequests.Value)
  125. availability := virtualServerStats.NestedStats.Entries.AvailabilityState.Description
  126. switch {
  127. case strings.HasPrefix(availability, "available"):
  128. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  129. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  130. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusAvailable)
  131. case strings.HasPrefix(availability, "offline"):
  132. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusOffline)
  133. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  134. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  135. default:
  136. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  137. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusUnknown)
  138. s.mb.RecordBigipVirtualServerAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  139. }
  140. enabled := virtualServerStats.NestedStats.Entries.EnabledState.Description
  141. if strings.HasPrefix(enabled, "enabled") {
  142. s.mb.RecordBigipVirtualServerEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusDisabled)
  143. s.mb.RecordBigipVirtualServerEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusEnabled)
  144. } else {
  145. s.mb.RecordBigipVirtualServerEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusDisabled)
  146. s.mb.RecordBigipVirtualServerEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusEnabled)
  147. }
  148. rb := s.mb.NewResourceBuilder()
  149. rb.SetBigipVirtualServerName(virtualServerStats.NestedStats.Entries.Name.Description)
  150. rb.SetBigipVirtualServerDestination(virtualServerStats.NestedStats.Entries.Destination.Description)
  151. rb.SetBigipPoolName(virtualServerStats.NestedStats.Entries.PoolName.Description)
  152. s.mb.EmitForResource(metadata.WithResource(rb.Emit()))
  153. }
  154. // collectPools collects pool metrics
  155. func (s *bigipScraper) collectPools(poolStats *models.PoolStats, now pcommon.Timestamp) {
  156. s.mb.RecordBigipPoolDataTransmittedDataPoint(now, poolStats.NestedStats.Entries.ServersideBitsIn.Value, metadata.AttributeDirectionReceived)
  157. s.mb.RecordBigipPoolDataTransmittedDataPoint(now, poolStats.NestedStats.Entries.ServersideBitsOut.Value, metadata.AttributeDirectionSent)
  158. s.mb.RecordBigipPoolConnectionCountDataPoint(now, poolStats.NestedStats.Entries.ServersideCurConns.Value)
  159. s.mb.RecordBigipPoolPacketCountDataPoint(now, poolStats.NestedStats.Entries.ServersidePktsIn.Value, metadata.AttributeDirectionReceived)
  160. s.mb.RecordBigipPoolPacketCountDataPoint(now, poolStats.NestedStats.Entries.ServersidePktsOut.Value, metadata.AttributeDirectionSent)
  161. s.mb.RecordBigipPoolRequestCountDataPoint(now, poolStats.NestedStats.Entries.TotalRequests.Value)
  162. s.mb.RecordBigipPoolMemberCountDataPoint(now, poolStats.NestedStats.Entries.ActiveMemberCount.Value, metadata.AttributeActiveStatusActive)
  163. inactiveCount := poolStats.NestedStats.Entries.TotalMemberCount.Value - poolStats.NestedStats.Entries.ActiveMemberCount.Value
  164. s.mb.RecordBigipPoolMemberCountDataPoint(now, inactiveCount, metadata.AttributeActiveStatusInactive)
  165. availability := poolStats.NestedStats.Entries.AvailabilityState.Description
  166. switch {
  167. case strings.HasPrefix(availability, "available"):
  168. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  169. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  170. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusAvailable)
  171. case strings.HasPrefix(availability, "offline"):
  172. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusOffline)
  173. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  174. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  175. default:
  176. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  177. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusUnknown)
  178. s.mb.RecordBigipPoolAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  179. }
  180. enabled := poolStats.NestedStats.Entries.EnabledState.Description
  181. if strings.HasPrefix(enabled, "enabled") {
  182. s.mb.RecordBigipPoolEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusDisabled)
  183. s.mb.RecordBigipPoolEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusEnabled)
  184. } else {
  185. s.mb.RecordBigipPoolEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusDisabled)
  186. s.mb.RecordBigipPoolEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusEnabled)
  187. }
  188. rb := s.mb.NewResourceBuilder()
  189. rb.SetBigipPoolName(poolStats.NestedStats.Entries.Name.Description)
  190. s.mb.EmitForResource(metadata.WithResource(rb.Emit()))
  191. }
  192. // collectPoolMembers collects pool member metrics
  193. func (s *bigipScraper) collectPoolMembers(poolMemberStats *models.PoolMemberStats, now pcommon.Timestamp) {
  194. s.mb.RecordBigipPoolMemberDataTransmittedDataPoint(now, poolMemberStats.NestedStats.Entries.ServersideBitsIn.Value, metadata.AttributeDirectionReceived)
  195. s.mb.RecordBigipPoolMemberDataTransmittedDataPoint(now, poolMemberStats.NestedStats.Entries.ServersideBitsOut.Value, metadata.AttributeDirectionSent)
  196. s.mb.RecordBigipPoolMemberConnectionCountDataPoint(now, poolMemberStats.NestedStats.Entries.ServersideCurConns.Value)
  197. s.mb.RecordBigipPoolMemberPacketCountDataPoint(now, poolMemberStats.NestedStats.Entries.ServersidePktsIn.Value, metadata.AttributeDirectionReceived)
  198. s.mb.RecordBigipPoolMemberPacketCountDataPoint(now, poolMemberStats.NestedStats.Entries.ServersidePktsOut.Value, metadata.AttributeDirectionSent)
  199. s.mb.RecordBigipPoolMemberRequestCountDataPoint(now, poolMemberStats.NestedStats.Entries.TotalRequests.Value)
  200. s.mb.RecordBigipPoolMemberSessionCountDataPoint(now, poolMemberStats.NestedStats.Entries.CurSessions.Value)
  201. availability := poolMemberStats.NestedStats.Entries.AvailabilityState.Description
  202. switch {
  203. case strings.HasPrefix(availability, "available"):
  204. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  205. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  206. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusAvailable)
  207. case strings.HasPrefix(availability, "offline"):
  208. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusOffline)
  209. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  210. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  211. default:
  212. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  213. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusUnknown)
  214. s.mb.RecordBigipPoolMemberAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  215. }
  216. enabled := poolMemberStats.NestedStats.Entries.EnabledState.Description
  217. if strings.HasPrefix(enabled, "enabled") {
  218. s.mb.RecordBigipPoolMemberEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusDisabled)
  219. s.mb.RecordBigipPoolMemberEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusEnabled)
  220. } else {
  221. s.mb.RecordBigipPoolMemberEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusDisabled)
  222. s.mb.RecordBigipPoolMemberEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusEnabled)
  223. }
  224. rb := s.mb.NewResourceBuilder()
  225. rb.SetBigipPoolMemberName(fmt.Sprintf("%s:%d", poolMemberStats.NestedStats.Entries.Name.Description, poolMemberStats.NestedStats.Entries.Port.Value))
  226. rb.SetBigipPoolMemberIPAddress(poolMemberStats.NestedStats.Entries.IPAddress.Description)
  227. rb.SetBigipPoolName(poolMemberStats.NestedStats.Entries.PoolName.Description)
  228. s.mb.EmitForResource(metadata.WithResource(rb.Emit()))
  229. }
  230. // collectNodes collects node metrics
  231. func (s *bigipScraper) collectNodes(nodeStats *models.NodeStats, now pcommon.Timestamp) {
  232. s.mb.RecordBigipNodeDataTransmittedDataPoint(now, nodeStats.NestedStats.Entries.ServersideBitsIn.Value, metadata.AttributeDirectionReceived)
  233. s.mb.RecordBigipNodeDataTransmittedDataPoint(now, nodeStats.NestedStats.Entries.ServersideBitsOut.Value, metadata.AttributeDirectionSent)
  234. s.mb.RecordBigipNodeConnectionCountDataPoint(now, nodeStats.NestedStats.Entries.ServersideCurConns.Value)
  235. s.mb.RecordBigipNodePacketCountDataPoint(now, nodeStats.NestedStats.Entries.ServersidePktsIn.Value, metadata.AttributeDirectionReceived)
  236. s.mb.RecordBigipNodePacketCountDataPoint(now, nodeStats.NestedStats.Entries.ServersidePktsOut.Value, metadata.AttributeDirectionSent)
  237. s.mb.RecordBigipNodeRequestCountDataPoint(now, nodeStats.NestedStats.Entries.TotalRequests.Value)
  238. s.mb.RecordBigipNodeSessionCountDataPoint(now, nodeStats.NestedStats.Entries.CurSessions.Value)
  239. availability := nodeStats.NestedStats.Entries.AvailabilityState.Description
  240. switch {
  241. case strings.HasPrefix(availability, "available"):
  242. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  243. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  244. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusAvailable)
  245. case strings.HasPrefix(availability, "offline"):
  246. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusOffline)
  247. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusUnknown)
  248. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  249. default:
  250. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusOffline)
  251. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 1, metadata.AttributeAvailabilityStatusUnknown)
  252. s.mb.RecordBigipNodeAvailabilityDataPoint(now, 0, metadata.AttributeAvailabilityStatusAvailable)
  253. }
  254. enabled := nodeStats.NestedStats.Entries.EnabledState.Description
  255. if strings.HasPrefix(enabled, "enabled") {
  256. s.mb.RecordBigipNodeEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusDisabled)
  257. s.mb.RecordBigipNodeEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusEnabled)
  258. } else {
  259. s.mb.RecordBigipNodeEnabledDataPoint(now, 1, metadata.AttributeEnabledStatusDisabled)
  260. s.mb.RecordBigipNodeEnabledDataPoint(now, 0, metadata.AttributeEnabledStatusEnabled)
  261. }
  262. rb := s.mb.NewResourceBuilder()
  263. rb.SetBigipNodeName(nodeStats.NestedStats.Entries.Name.Description)
  264. rb.SetBigipNodeIPAddress(nodeStats.NestedStats.Entries.IPAddress.Description)
  265. s.mb.EmitForResource(metadata.WithResource(rb.Emit()))
  266. }