mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-30 04:42:01 +08:00
334 lines
8.6 KiB
Go
334 lines
8.6 KiB
Go
package cloudintegrations
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/SigNoz/signoz/pkg/types"
|
|
)
|
|
|
|
// Represents a cloud provider account for cloud integrations
|
|
type AccountRecord struct {
|
|
CloudProvider string `json:"cloud_provider" db:"cloud_provider"`
|
|
Id string `json:"id" db:"id"`
|
|
Config *AccountConfig `json:"config" db:"config_json"`
|
|
CloudAccountId *string `json:"cloud_account_id" db:"cloud_account_id"`
|
|
LastAgentReport *AgentReport `json:"last_agent_report" db:"last_agent_report_json"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
RemovedAt *time.Time `json:"removed_at" db:"removed_at"`
|
|
}
|
|
|
|
type AccountConfig struct {
|
|
EnabledRegions []string `json:"regions"`
|
|
}
|
|
|
|
func DefaultAccountConfig() AccountConfig {
|
|
return AccountConfig{
|
|
EnabledRegions: []string{},
|
|
}
|
|
}
|
|
|
|
// For serializing from db
|
|
func (c *AccountConfig) Scan(src any) error {
|
|
data, ok := src.([]byte)
|
|
if !ok {
|
|
return fmt.Errorf("tried to scan from %T instead of bytes", src)
|
|
}
|
|
|
|
return json.Unmarshal(data, &c)
|
|
}
|
|
|
|
// For serializing to db
|
|
func (c *AccountConfig) Value() (driver.Value, error) {
|
|
if c == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
serialized, err := json.Marshal(c)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"couldn't serialize cloud account config to JSON: %w", err,
|
|
)
|
|
}
|
|
return serialized, nil
|
|
}
|
|
|
|
type AgentReport struct {
|
|
TimestampMillis int64 `json:"timestamp_millis"`
|
|
Data map[string]any `json:"data"`
|
|
}
|
|
|
|
// For serializing from db
|
|
func (r *AgentReport) Scan(src any) error {
|
|
data, ok := src.([]byte)
|
|
if !ok {
|
|
return fmt.Errorf("tried to scan from %T instead of bytes", src)
|
|
}
|
|
|
|
return json.Unmarshal(data, &r)
|
|
}
|
|
|
|
// For serializing to db
|
|
func (r *AgentReport) Value() (driver.Value, error) {
|
|
if r == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
serialized, err := json.Marshal(r)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"couldn't serialize agent report to JSON: %w", err,
|
|
)
|
|
}
|
|
return serialized, nil
|
|
}
|
|
|
|
type AccountStatus struct {
|
|
Integration AccountIntegrationStatus `json:"integration"`
|
|
}
|
|
|
|
type AccountIntegrationStatus struct {
|
|
LastHeartbeatTsMillis *int64 `json:"last_heartbeat_ts_ms"`
|
|
}
|
|
|
|
func (a *AccountRecord) status() AccountStatus {
|
|
status := AccountStatus{}
|
|
if a.LastAgentReport != nil {
|
|
lastHeartbeat := a.LastAgentReport.TimestampMillis
|
|
status.Integration.LastHeartbeatTsMillis = &lastHeartbeat
|
|
}
|
|
return status
|
|
}
|
|
|
|
func (a *AccountRecord) account() Account {
|
|
ca := Account{Id: a.Id, Status: a.status()}
|
|
|
|
if a.CloudAccountId != nil {
|
|
ca.CloudAccountId = *a.CloudAccountId
|
|
}
|
|
|
|
if a.Config != nil {
|
|
ca.Config = *a.Config
|
|
} else {
|
|
ca.Config = DefaultAccountConfig()
|
|
}
|
|
|
|
return ca
|
|
}
|
|
|
|
type CloudServiceSummary struct {
|
|
Id string `json:"id"`
|
|
Title string `json:"title"`
|
|
Icon string `json:"icon"`
|
|
|
|
// Present only if the service has been configured in the
|
|
// context of a cloud provider account.
|
|
Config *CloudServiceConfig `json:"config,omitempty"`
|
|
}
|
|
|
|
type CloudServiceDetails struct {
|
|
CloudServiceSummary
|
|
|
|
Overview string `json:"overview"` // markdown
|
|
|
|
Assets CloudServiceAssets `json:"assets"`
|
|
|
|
SupportedSignals SupportedSignals `json:"supported_signals"`
|
|
|
|
DataCollected DataCollectedForService `json:"data_collected"`
|
|
|
|
ConnectionStatus *CloudServiceConnectionStatus `json:"status,omitempty"`
|
|
|
|
TelemetryCollectionStrategy *CloudTelemetryCollectionStrategy `json:"telemetry_collection_strategy"`
|
|
}
|
|
|
|
type CloudServiceConfig struct {
|
|
Logs *CloudServiceLogsConfig `json:"logs,omitempty"`
|
|
Metrics *CloudServiceMetricsConfig `json:"metrics,omitempty"`
|
|
}
|
|
|
|
// For serializing from db
|
|
func (c *CloudServiceConfig) Scan(src any) error {
|
|
data, ok := src.([]byte)
|
|
if !ok {
|
|
return fmt.Errorf("tried to scan from %T instead of bytes", src)
|
|
}
|
|
|
|
return json.Unmarshal(data, &c)
|
|
}
|
|
|
|
// For serializing to db
|
|
func (c *CloudServiceConfig) Value() (driver.Value, error) {
|
|
if c == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
serialized, err := json.Marshal(c)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"couldn't serialize cloud service config to JSON: %w", err,
|
|
)
|
|
}
|
|
return serialized, nil
|
|
}
|
|
|
|
type CloudServiceLogsConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
type CloudServiceMetricsConfig struct {
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
|
|
type CloudServiceAssets struct {
|
|
Dashboards []CloudServiceDashboard `json:"dashboards"`
|
|
}
|
|
|
|
type CloudServiceDashboard struct {
|
|
Id string `json:"id"`
|
|
Url string `json:"url"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description"`
|
|
Image string `json:"image"`
|
|
Definition *types.DashboardData `json:"definition,omitempty"`
|
|
}
|
|
|
|
type SupportedSignals struct {
|
|
Logs bool `json:"logs"`
|
|
Metrics bool `json:"metrics"`
|
|
}
|
|
|
|
type DataCollectedForService struct {
|
|
Logs []CollectedLogAttribute `json:"logs"`
|
|
Metrics []CollectedMetric `json:"metrics"`
|
|
}
|
|
|
|
type CollectedLogAttribute struct {
|
|
Name string `json:"name"`
|
|
Path string `json:"path"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
type CollectedMetric struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Unit string `json:"unit"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
type CloudServiceConnectionStatus struct {
|
|
Logs *SignalConnectionStatus `json:"logs"`
|
|
Metrics *SignalConnectionStatus `json:"metrics"`
|
|
}
|
|
|
|
type SignalConnectionStatus struct {
|
|
LastReceivedTsMillis int64 `json:"last_received_ts_ms"` // epoch milliseconds
|
|
LastReceivedFrom string `json:"last_received_from"` // resource identifier
|
|
}
|
|
|
|
type CloudTelemetryCollectionStrategy struct {
|
|
Provider string `json:"provider"`
|
|
|
|
AWSMetrics *AWSMetricsCollectionStrategy `json:"aws_metrics,omitempty"`
|
|
AWSLogs *AWSLogsCollectionStrategy `json:"aws_logs,omitempty"`
|
|
}
|
|
|
|
func NewCloudTelemetryCollectionStrategy(provider string) (*CloudTelemetryCollectionStrategy, error) {
|
|
if provider == "aws" {
|
|
return &CloudTelemetryCollectionStrategy{
|
|
Provider: "aws",
|
|
AWSMetrics: &AWSMetricsCollectionStrategy{
|
|
CloudwatchMetricsStreamFilters: []CloudwatchMetricStreamFilter{},
|
|
},
|
|
AWSLogs: &AWSLogsCollectionStrategy{
|
|
CloudwatchLogsSubscriptions: []CloudwatchLogsSubscriptionConfig{},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("unsupported cloud provider: %s", provider)
|
|
}
|
|
|
|
// Helper for accumulating strategies for enabled services.
|
|
func (cs *CloudTelemetryCollectionStrategy) AddServiceStrategy(
|
|
svcStrategy *CloudTelemetryCollectionStrategy,
|
|
logsEnabled bool,
|
|
metricsEnabled bool,
|
|
) error {
|
|
if svcStrategy.Provider != cs.Provider {
|
|
return fmt.Errorf(
|
|
"can't add %s service strategy to strategy for %s",
|
|
svcStrategy.Provider, cs.Provider,
|
|
)
|
|
}
|
|
|
|
if cs.Provider == "aws" {
|
|
if logsEnabled {
|
|
cs.AWSLogs.AddServiceStrategy(svcStrategy.AWSLogs)
|
|
}
|
|
if metricsEnabled {
|
|
cs.AWSMetrics.AddServiceStrategy(svcStrategy.AWSMetrics)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("unsupported cloud provider: %s", cs.Provider)
|
|
|
|
}
|
|
|
|
type AWSMetricsCollectionStrategy struct {
|
|
// to be used as https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudwatch-metricstream.html#cfn-cloudwatch-metricstream-includefilters
|
|
CloudwatchMetricsStreamFilters []CloudwatchMetricStreamFilter `json:"cloudwatch_metric_stream_filters"`
|
|
}
|
|
|
|
type CloudwatchMetricStreamFilter struct {
|
|
// json tags here are in the shape expected by AWS API as detailed at
|
|
// https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudwatch-metricstream-metricstreamfilter.html
|
|
Namespace string `json:"Namespace"`
|
|
MetricNames []string `json:"MetricNames,omitempty"`
|
|
}
|
|
|
|
func (amc *AWSMetricsCollectionStrategy) AddServiceStrategy(
|
|
svcStrategy *AWSMetricsCollectionStrategy,
|
|
) error {
|
|
if svcStrategy == nil {
|
|
return nil
|
|
}
|
|
|
|
amc.CloudwatchMetricsStreamFilters = append(
|
|
amc.CloudwatchMetricsStreamFilters,
|
|
svcStrategy.CloudwatchMetricsStreamFilters...,
|
|
)
|
|
return nil
|
|
}
|
|
|
|
type AWSLogsCollectionStrategy struct {
|
|
CloudwatchLogsSubscriptions []CloudwatchLogsSubscriptionConfig `json:"cloudwatch_logs_subscriptions"`
|
|
}
|
|
|
|
type CloudwatchLogsSubscriptionConfig struct {
|
|
// subscribe to all logs groups with specified prefix.
|
|
// eg: `/aws/rds/`
|
|
LogGroupNamePrefix string `json:"log_group_name_prefix"`
|
|
|
|
// https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html
|
|
// "" implies no filtering is required.
|
|
FilterPattern string `json:"filter_pattern"`
|
|
}
|
|
|
|
func (alc *AWSLogsCollectionStrategy) AddServiceStrategy(
|
|
svcStrategy *AWSLogsCollectionStrategy,
|
|
) error {
|
|
if svcStrategy == nil {
|
|
return nil
|
|
}
|
|
|
|
alc.CloudwatchLogsSubscriptions = append(
|
|
alc.CloudwatchLogsSubscriptions,
|
|
svcStrategy.CloudwatchLogsSubscriptions...,
|
|
)
|
|
return nil
|
|
}
|