mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-31 17:51:57 +08:00
chore: move channel management from CH reader to rule DB (#5934)
This commit is contained in:
parent
b78ade2cf2
commit
f8e97c9c5c
@ -1,15 +1,12 @@
|
|||||||
package clickhouseReader
|
package clickhouseReader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -173,7 +170,7 @@ func NewReaderFromClickhouseConnection(
|
|||||||
cluster string,
|
cluster string,
|
||||||
useLogsNewSchema bool,
|
useLogsNewSchema bool,
|
||||||
) *ClickHouseReader {
|
) *ClickHouseReader {
|
||||||
alertManager, err := am.New("")
|
alertManager, err := am.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.L().Error("failed to initialize alert manager", zap.Error(err))
|
zap.L().Error("failed to initialize alert manager", zap.Error(err))
|
||||||
zap.L().Error("check if the alert manager URL is correctly set and valid")
|
zap.L().Error("check if the alert manager URL is correctly set and valid")
|
||||||
@ -414,267 +411,6 @@ func (r *ClickHouseReader) GetConn() clickhouse.Conn {
|
|||||||
return r.db
|
return r.db
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ClickHouseReader) LoadChannel(channel *model.ChannelItem) *model.ApiError {
|
|
||||||
|
|
||||||
receiver := &am.Receiver{}
|
|
||||||
if err := json.Unmarshal([]byte(channel.Data), receiver); err != nil { // Parse []byte to go struct pointer
|
|
||||||
return &model.ApiError{Typ: model.ErrorBadData, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := http.Post(constants.GetAlertManagerApiPrefix()+"v1/receivers", "application/json", bytes.NewBuffer([]byte(channel.Data)))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in getting response of API call to alertmanager/v1/receivers", zap.Error(err))
|
|
||||||
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
if response.StatusCode > 299 {
|
|
||||||
responseData, _ := io.ReadAll(response.Body)
|
|
||||||
|
|
||||||
err := fmt.Errorf("error in getting 2xx response in API call to alertmanager/v1/receivers")
|
|
||||||
zap.L().Error("Error in getting 2xx response in API call to alertmanager/v1/receivers", zap.String("Status", response.Status), zap.String("Data", string(responseData)))
|
|
||||||
|
|
||||||
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ClickHouseReader) GetChannel(id string) (*model.ChannelItem, *model.ApiError) {
|
|
||||||
|
|
||||||
idInt, _ := strconv.Atoi(id)
|
|
||||||
channel := model.ChannelItem{}
|
|
||||||
|
|
||||||
query := "SELECT id, created_at, updated_at, name, type, data data FROM notification_channels WHERE id=? "
|
|
||||||
|
|
||||||
stmt, err := r.localDB.Preparex(query)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in preparing sql query for GetChannel", zap.Error(err))
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = stmt.Get(&channel, idInt)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in getting channel with id", zap.Int("id", idInt), zap.Error(err))
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &channel, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ClickHouseReader) DeleteChannel(id string) *model.ApiError {
|
|
||||||
|
|
||||||
idInt, _ := strconv.Atoi(id)
|
|
||||||
|
|
||||||
channelToDelete, apiErrorObj := r.GetChannel(id)
|
|
||||||
|
|
||||||
if apiErrorObj != nil {
|
|
||||||
return apiErrorObj
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := r.localDB.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
stmt, err := tx.Prepare(`DELETE FROM notification_channels WHERE id=$1;`)
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in preparing statement for INSERT to notification_channels", zap.Error(err))
|
|
||||||
tx.Rollback()
|
|
||||||
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
defer stmt.Close()
|
|
||||||
|
|
||||||
if _, err := stmt.Exec(idInt); err != nil {
|
|
||||||
zap.L().Error("Error in Executing prepared statement for INSERT to notification_channels", zap.Error(err))
|
|
||||||
tx.Rollback() // return an error too, we may want to wrap them
|
|
||||||
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apiError := r.alertManager.DeleteRoute(channelToDelete.Name)
|
|
||||||
if apiError != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
return apiError
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tx.Commit()
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in committing transaction for DELETE command to notification_channels", zap.Error(err))
|
|
||||||
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ClickHouseReader) GetChannels() (*[]model.ChannelItem, *model.ApiError) {
|
|
||||||
|
|
||||||
channels := []model.ChannelItem{}
|
|
||||||
|
|
||||||
query := "SELECT id, created_at, updated_at, name, type, data data FROM notification_channels"
|
|
||||||
|
|
||||||
err := r.localDB.Select(&channels, query)
|
|
||||||
|
|
||||||
zap.L().Info(query)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in processing sql query", zap.Error(err))
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &channels, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func getChannelType(receiver *am.Receiver) string {
|
|
||||||
|
|
||||||
if receiver.EmailConfigs != nil {
|
|
||||||
return "email"
|
|
||||||
}
|
|
||||||
if receiver.OpsGenieConfigs != nil {
|
|
||||||
return "opsgenie"
|
|
||||||
}
|
|
||||||
if receiver.PagerdutyConfigs != nil {
|
|
||||||
return "pagerduty"
|
|
||||||
}
|
|
||||||
if receiver.PushoverConfigs != nil {
|
|
||||||
return "pushover"
|
|
||||||
}
|
|
||||||
if receiver.SNSConfigs != nil {
|
|
||||||
return "sns"
|
|
||||||
}
|
|
||||||
if receiver.SlackConfigs != nil {
|
|
||||||
return "slack"
|
|
||||||
}
|
|
||||||
if receiver.VictorOpsConfigs != nil {
|
|
||||||
return "victorops"
|
|
||||||
}
|
|
||||||
if receiver.WebhookConfigs != nil {
|
|
||||||
return "webhook"
|
|
||||||
}
|
|
||||||
if receiver.WechatConfigs != nil {
|
|
||||||
return "wechat"
|
|
||||||
}
|
|
||||||
if receiver.MSTeamsConfigs != nil {
|
|
||||||
return "msteams"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ClickHouseReader) EditChannel(receiver *am.Receiver, id string) (*am.Receiver, *model.ApiError) {
|
|
||||||
|
|
||||||
idInt, _ := strconv.Atoi(id)
|
|
||||||
|
|
||||||
channel, apiErrObj := r.GetChannel(id)
|
|
||||||
|
|
||||||
if apiErrObj != nil {
|
|
||||||
return nil, apiErrObj
|
|
||||||
}
|
|
||||||
if channel.Name != receiver.Name {
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("channel name cannot be changed")}
|
|
||||||
}
|
|
||||||
|
|
||||||
tx, err := r.localDB.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
channel_type := getChannelType(receiver)
|
|
||||||
|
|
||||||
// check if channel type is supported in the current user plan
|
|
||||||
if err := r.featureFlags.CheckFeature(fmt.Sprintf("ALERT_CHANNEL_%s", strings.ToUpper(channel_type))); err != nil {
|
|
||||||
zap.L().Warn("an unsupported feature was blocked", zap.Error(err))
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("unsupported feature. please upgrade your plan to access this feature")}
|
|
||||||
}
|
|
||||||
|
|
||||||
receiverString, _ := json.Marshal(receiver)
|
|
||||||
|
|
||||||
{
|
|
||||||
stmt, err := tx.Prepare(`UPDATE notification_channels SET updated_at=$1, type=$2, data=$3 WHERE id=$4;`)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in preparing statement for UPDATE to notification_channels", zap.Error(err))
|
|
||||||
tx.Rollback()
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
defer stmt.Close()
|
|
||||||
|
|
||||||
if _, err := stmt.Exec(time.Now(), channel_type, string(receiverString), idInt); err != nil {
|
|
||||||
zap.L().Error("Error in Executing prepared statement for UPDATE to notification_channels", zap.Error(err))
|
|
||||||
tx.Rollback() // return an error too, we may want to wrap them
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apiError := r.alertManager.EditRoute(receiver)
|
|
||||||
if apiError != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
return nil, apiError
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tx.Commit()
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in committing transaction for INSERT to notification_channels", zap.Error(err))
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return receiver, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ClickHouseReader) CreateChannel(receiver *am.Receiver) (*am.Receiver, *model.ApiError) {
|
|
||||||
|
|
||||||
channel_type := getChannelType(receiver)
|
|
||||||
|
|
||||||
// check if channel type is supported in the current user plan
|
|
||||||
if err := r.featureFlags.CheckFeature(fmt.Sprintf("ALERT_CHANNEL_%s", strings.ToUpper(channel_type))); err != nil {
|
|
||||||
zap.L().Warn("an unsupported feature was blocked", zap.Error(err))
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("unsupported feature. please upgrade your plan to access this feature")}
|
|
||||||
}
|
|
||||||
|
|
||||||
receiverString, _ := json.Marshal(receiver)
|
|
||||||
|
|
||||||
tx, err := r.localDB.Begin()
|
|
||||||
if err != nil {
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
stmt, err := tx.Prepare(`INSERT INTO notification_channels (created_at, updated_at, name, type, data) VALUES($1,$2,$3,$4,$5);`)
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in preparing statement for INSERT to notification_channels", zap.Error(err))
|
|
||||||
tx.Rollback()
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
defer stmt.Close()
|
|
||||||
|
|
||||||
if _, err := stmt.Exec(time.Now(), time.Now(), receiver.Name, channel_type, string(receiverString)); err != nil {
|
|
||||||
zap.L().Error("Error in Executing prepared statement for INSERT to notification_channels", zap.Error(err))
|
|
||||||
tx.Rollback() // return an error too, we may want to wrap them
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apiError := r.alertManager.AddRoute(receiver)
|
|
||||||
if apiError != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
return nil, apiError
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tx.Commit()
|
|
||||||
if err != nil {
|
|
||||||
zap.L().Error("Error in committing transaction for INSERT to notification_channels", zap.Error(err))
|
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return receiver, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ClickHouseReader) GetInstantQueryMetricsResult(ctx context.Context, queryParams *model.InstantQueryMetricsParams) (*promql.Result, *stats.QueryStats, *model.ApiError) {
|
func (r *ClickHouseReader) GetInstantQueryMetricsResult(ctx context.Context, queryParams *model.InstantQueryMetricsParams) (*promql.Result, *stats.QueryStats, *model.ApiError) {
|
||||||
qry, err := r.queryEngine.NewInstantQuery(ctx, r.remoteStorage, nil, queryParams.Query, queryParams.Time)
|
qry, err := r.queryEngine.NewInstantQuery(ctx, r.remoteStorage, nil, queryParams.Query, queryParams.Time)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -151,7 +151,7 @@ type APIHandlerOpts struct {
|
|||||||
// NewAPIHandler returns an APIHandler
|
// NewAPIHandler returns an APIHandler
|
||||||
func NewAPIHandler(opts APIHandlerOpts) (*APIHandler, error) {
|
func NewAPIHandler(opts APIHandlerOpts) (*APIHandler, error) {
|
||||||
|
|
||||||
alertManager, err := am.New("")
|
alertManager, err := am.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1182,7 +1182,7 @@ func (aH *APIHandler) editRule(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (aH *APIHandler) getChannel(w http.ResponseWriter, r *http.Request) {
|
func (aH *APIHandler) getChannel(w http.ResponseWriter, r *http.Request) {
|
||||||
id := mux.Vars(r)["id"]
|
id := mux.Vars(r)["id"]
|
||||||
channel, apiErrorObj := aH.reader.GetChannel(id)
|
channel, apiErrorObj := aH.ruleManager.RuleDB().GetChannel(id)
|
||||||
if apiErrorObj != nil {
|
if apiErrorObj != nil {
|
||||||
RespondError(w, apiErrorObj, nil)
|
RespondError(w, apiErrorObj, nil)
|
||||||
return
|
return
|
||||||
@ -1192,7 +1192,7 @@ func (aH *APIHandler) getChannel(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (aH *APIHandler) deleteChannel(w http.ResponseWriter, r *http.Request) {
|
func (aH *APIHandler) deleteChannel(w http.ResponseWriter, r *http.Request) {
|
||||||
id := mux.Vars(r)["id"]
|
id := mux.Vars(r)["id"]
|
||||||
apiErrorObj := aH.reader.DeleteChannel(id)
|
apiErrorObj := aH.ruleManager.RuleDB().DeleteChannel(id)
|
||||||
if apiErrorObj != nil {
|
if apiErrorObj != nil {
|
||||||
RespondError(w, apiErrorObj, nil)
|
RespondError(w, apiErrorObj, nil)
|
||||||
return
|
return
|
||||||
@ -1201,7 +1201,7 @@ func (aH *APIHandler) deleteChannel(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (aH *APIHandler) listChannels(w http.ResponseWriter, r *http.Request) {
|
func (aH *APIHandler) listChannels(w http.ResponseWriter, r *http.Request) {
|
||||||
channels, apiErrorObj := aH.reader.GetChannels()
|
channels, apiErrorObj := aH.ruleManager.RuleDB().GetChannels()
|
||||||
if apiErrorObj != nil {
|
if apiErrorObj != nil {
|
||||||
RespondError(w, apiErrorObj, nil)
|
RespondError(w, apiErrorObj, nil)
|
||||||
return
|
return
|
||||||
@ -1254,7 +1254,7 @@ func (aH *APIHandler) editChannel(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, apiErrorObj := aH.reader.EditChannel(receiver, id)
|
_, apiErrorObj := aH.ruleManager.RuleDB().EditChannel(receiver, id)
|
||||||
|
|
||||||
if apiErrorObj != nil {
|
if apiErrorObj != nil {
|
||||||
RespondError(w, apiErrorObj, nil)
|
RespondError(w, apiErrorObj, nil)
|
||||||
@ -1282,7 +1282,7 @@ func (aH *APIHandler) createChannel(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, apiErrorObj := aH.reader.CreateChannel(receiver)
|
_, apiErrorObj := aH.ruleManager.RuleDB().CreateChannel(receiver)
|
||||||
|
|
||||||
if apiErrorObj != nil {
|
if apiErrorObj != nil {
|
||||||
RespondError(w, apiErrorObj, nil)
|
RespondError(w, apiErrorObj, nil)
|
||||||
|
@ -24,42 +24,62 @@ type Manager interface {
|
|||||||
TestReceiver(receiver *Receiver) *model.ApiError
|
TestReceiver(receiver *Receiver) *model.ApiError
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(url string) (Manager, error) {
|
func defaultOptions() []ManagerOptions {
|
||||||
|
return []ManagerOptions{
|
||||||
|
WithURL(constants.GetAlertManagerApiPrefix()),
|
||||||
|
WithChannelApiPath(constants.AmChannelApiPath),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if url == "" {
|
type ManagerOptions func(m *manager) error
|
||||||
url = constants.GetAlertManagerApiPrefix()
|
|
||||||
|
func New(opts ...ManagerOptions) (Manager, error) {
|
||||||
|
m := &manager{}
|
||||||
|
|
||||||
|
newOpts := defaultOptions()
|
||||||
|
newOpts = append(newOpts, opts...)
|
||||||
|
|
||||||
|
for _, opt := range newOpts {
|
||||||
|
err := opt(m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
urlParsed, err := neturl.Parse(url)
|
return m, nil
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &manager{
|
func WithURL(url string) ManagerOptions {
|
||||||
url: url,
|
return func(m *manager) error {
|
||||||
parsedURL: urlParsed,
|
m.url = url
|
||||||
}, nil
|
parsedURL, err := neturl.Parse(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.parsedURL = parsedURL
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithChannelApiPath(path string) ManagerOptions {
|
||||||
|
return func(m *manager) error {
|
||||||
|
m.channelApiPath = path
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type manager struct {
|
type manager struct {
|
||||||
url string
|
url string
|
||||||
parsedURL *neturl.URL
|
parsedURL *neturl.URL
|
||||||
|
channelApiPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareAmChannelApiURL() string {
|
func (m *manager) prepareAmChannelApiURL() string {
|
||||||
basePath := constants.GetAlertManagerApiPrefix()
|
return fmt.Sprintf("%s%s", m.url, m.channelApiPath)
|
||||||
AmChannelApiPath := constants.AmChannelApiPath
|
|
||||||
|
|
||||||
if len(AmChannelApiPath) > 0 && rune(AmChannelApiPath[0]) == rune('/') {
|
|
||||||
AmChannelApiPath = AmChannelApiPath[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s%s", basePath, AmChannelApiPath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareTestApiURL() string {
|
func (m *manager) prepareTestApiURL() string {
|
||||||
basePath := constants.GetAlertManagerApiPrefix()
|
return fmt.Sprintf("%s%s", m.url, "v1/testReceiver")
|
||||||
return fmt.Sprintf("%s%s", basePath, "v1/testReceiver")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) URL() *neturl.URL {
|
func (m *manager) URL() *neturl.URL {
|
||||||
@ -79,7 +99,7 @@ func (m *manager) AddRoute(receiver *Receiver) *model.ApiError {
|
|||||||
|
|
||||||
receiverString, _ := json.Marshal(receiver)
|
receiverString, _ := json.Marshal(receiver)
|
||||||
|
|
||||||
amURL := prepareAmChannelApiURL()
|
amURL := m.prepareAmChannelApiURL()
|
||||||
response, err := http.Post(amURL, contentType, bytes.NewBuffer(receiverString))
|
response, err := http.Post(amURL, contentType, bytes.NewBuffer(receiverString))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -97,7 +117,7 @@ func (m *manager) AddRoute(receiver *Receiver) *model.ApiError {
|
|||||||
func (m *manager) EditRoute(receiver *Receiver) *model.ApiError {
|
func (m *manager) EditRoute(receiver *Receiver) *model.ApiError {
|
||||||
receiverString, _ := json.Marshal(receiver)
|
receiverString, _ := json.Marshal(receiver)
|
||||||
|
|
||||||
amURL := prepareAmChannelApiURL()
|
amURL := m.prepareAmChannelApiURL()
|
||||||
req, err := http.NewRequest(http.MethodPut, amURL, bytes.NewBuffer(receiverString))
|
req, err := http.NewRequest(http.MethodPut, amURL, bytes.NewBuffer(receiverString))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -126,7 +146,7 @@ func (m *manager) DeleteRoute(name string) *model.ApiError {
|
|||||||
values := map[string]string{"name": name}
|
values := map[string]string{"name": name}
|
||||||
requestData, _ := json.Marshal(values)
|
requestData, _ := json.Marshal(values)
|
||||||
|
|
||||||
amURL := prepareAmChannelApiURL()
|
amURL := m.prepareAmChannelApiURL()
|
||||||
req, err := http.NewRequest(http.MethodDelete, amURL, bytes.NewBuffer(requestData))
|
req, err := http.NewRequest(http.MethodDelete, amURL, bytes.NewBuffer(requestData))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -156,7 +176,7 @@ func (m *manager) TestReceiver(receiver *Receiver) *model.ApiError {
|
|||||||
|
|
||||||
receiverBytes, _ := json.Marshal(receiver)
|
receiverBytes, _ := json.Marshal(receiver)
|
||||||
|
|
||||||
amTestURL := prepareTestApiURL()
|
amTestURL := m.prepareTestApiURL()
|
||||||
response, err := http.Post(amTestURL, contentType, bytes.NewBuffer(receiverBytes))
|
response, err := http.Post(amTestURL, contentType, bytes.NewBuffer(receiverBytes))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -295,7 +295,7 @@ func newAlertmanagerSet(urls []string, timeout time.Duration, logger log.Logger)
|
|||||||
|
|
||||||
ams := []Manager{}
|
ams := []Manager{}
|
||||||
for _, u := range urls {
|
for _, u := range urls {
|
||||||
am, err := New(u)
|
am, err := New(WithURL(u))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
level.Error(s.logger).Log(fmt.Sprintf("invalid alert manager url %s: %s", u, err))
|
level.Error(s.logger).Log(fmt.Sprintf("invalid alert manager url %s: %s", u, err))
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,18 +8,11 @@ import (
|
|||||||
"github.com/prometheus/prometheus/promql"
|
"github.com/prometheus/prometheus/promql"
|
||||||
"github.com/prometheus/prometheus/storage"
|
"github.com/prometheus/prometheus/storage"
|
||||||
"github.com/prometheus/prometheus/util/stats"
|
"github.com/prometheus/prometheus/util/stats"
|
||||||
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Reader interface {
|
type Reader interface {
|
||||||
GetChannel(id string) (*model.ChannelItem, *model.ApiError)
|
|
||||||
GetChannels() (*[]model.ChannelItem, *model.ApiError)
|
|
||||||
DeleteChannel(id string) *model.ApiError
|
|
||||||
CreateChannel(receiver *am.Receiver) (*am.Receiver, *model.ApiError)
|
|
||||||
EditChannel(receiver *am.Receiver, id string) (*am.Receiver, *model.ApiError)
|
|
||||||
|
|
||||||
GetInstantQueryMetricsResult(ctx context.Context, query *model.InstantQueryMetricsParams) (*promql.Result, *stats.QueryStats, *model.ApiError)
|
GetInstantQueryMetricsResult(ctx context.Context, query *model.InstantQueryMetricsParams) (*promql.Result, *stats.QueryStats, *model.ApiError)
|
||||||
GetQueryRangeResult(ctx context.Context, query *model.QueryRangeParams) (*promql.Result, *stats.QueryStats, *model.ApiError)
|
GetQueryRangeResult(ctx context.Context, query *model.QueryRangeParams) (*promql.Result, *stats.QueryStats, *model.ApiError)
|
||||||
GetServiceOverview(ctx context.Context, query *model.GetServiceOverviewParams, skipConfig *model.SkipConfig) (*[]model.ServiceOverviewItem, *model.ApiError)
|
GetServiceOverview(ctx context.Context, query *model.GetServiceOverviewParams, skipConfig *model.SkipConfig) (*[]model.ServiceOverviewItem, *model.ApiError)
|
||||||
|
@ -618,6 +618,7 @@ type AlertsInfo struct {
|
|||||||
LogsBasedAlerts int `json:"logsBasedAlerts"`
|
LogsBasedAlerts int `json:"logsBasedAlerts"`
|
||||||
MetricBasedAlerts int `json:"metricBasedAlerts"`
|
MetricBasedAlerts int `json:"metricBasedAlerts"`
|
||||||
TracesBasedAlerts int `json:"tracesBasedAlerts"`
|
TracesBasedAlerts int `json:"tracesBasedAlerts"`
|
||||||
|
TotalChannels int `json:"totalChannels"`
|
||||||
SlackChannels int `json:"slackChannels"`
|
SlackChannels int `json:"slackChannels"`
|
||||||
WebHookChannels int `json:"webHookChannels"`
|
WebHookChannels int `json:"webHookChannels"`
|
||||||
PagerDutyChannels int `json:"pagerDutyChannels"`
|
PagerDutyChannels int `json:"pagerDutyChannels"`
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"go.signoz.io/signoz/pkg/query-service/auth"
|
"go.signoz.io/signoz/pkg/query-service/auth"
|
||||||
"go.signoz.io/signoz/pkg/query-service/common"
|
"go.signoz.io/signoz/pkg/query-service/common"
|
||||||
|
am "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
|
||||||
"go.signoz.io/signoz/pkg/query-service/model"
|
"go.signoz.io/signoz/pkg/query-service/model"
|
||||||
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
v3 "go.signoz.io/signoz/pkg/query-service/model/v3"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -18,6 +19,12 @@ import (
|
|||||||
|
|
||||||
// Data store to capture user alert rule settings
|
// Data store to capture user alert rule settings
|
||||||
type RuleDB interface {
|
type RuleDB interface {
|
||||||
|
GetChannel(id string) (*model.ChannelItem, *model.ApiError)
|
||||||
|
GetChannels() (*[]model.ChannelItem, *model.ApiError)
|
||||||
|
DeleteChannel(id string) *model.ApiError
|
||||||
|
CreateChannel(receiver *am.Receiver) (*am.Receiver, *model.ApiError)
|
||||||
|
EditChannel(receiver *am.Receiver, id string) (*am.Receiver, *model.ApiError)
|
||||||
|
|
||||||
// CreateRuleTx stores rule in the db and returns tx and group name (on success)
|
// CreateRuleTx stores rule in the db and returns tx and group name (on success)
|
||||||
CreateRuleTx(ctx context.Context, rule string) (int64, Tx, error)
|
CreateRuleTx(ctx context.Context, rule string) (int64, Tx, error)
|
||||||
|
|
||||||
@ -68,13 +75,15 @@ type Tx interface {
|
|||||||
|
|
||||||
type ruleDB struct {
|
type ruleDB struct {
|
||||||
*sqlx.DB
|
*sqlx.DB
|
||||||
|
alertManager am.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: move init methods for creating tables
|
// todo: move init methods for creating tables
|
||||||
|
|
||||||
func NewRuleDB(db *sqlx.DB) RuleDB {
|
func NewRuleDB(db *sqlx.DB, alertManager am.Manager) RuleDB {
|
||||||
return &ruleDB{
|
return &ruleDB{
|
||||||
db,
|
db,
|
||||||
|
alertManager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,6 +312,229 @@ func (r *ruleDB) EditPlannedMaintenance(ctx context.Context, maintenance Planned
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getChannelType(receiver *am.Receiver) string {
|
||||||
|
|
||||||
|
if receiver.EmailConfigs != nil {
|
||||||
|
return "email"
|
||||||
|
}
|
||||||
|
if receiver.OpsGenieConfigs != nil {
|
||||||
|
return "opsgenie"
|
||||||
|
}
|
||||||
|
if receiver.PagerdutyConfigs != nil {
|
||||||
|
return "pagerduty"
|
||||||
|
}
|
||||||
|
if receiver.PushoverConfigs != nil {
|
||||||
|
return "pushover"
|
||||||
|
}
|
||||||
|
if receiver.SNSConfigs != nil {
|
||||||
|
return "sns"
|
||||||
|
}
|
||||||
|
if receiver.SlackConfigs != nil {
|
||||||
|
return "slack"
|
||||||
|
}
|
||||||
|
if receiver.VictorOpsConfigs != nil {
|
||||||
|
return "victorops"
|
||||||
|
}
|
||||||
|
if receiver.WebhookConfigs != nil {
|
||||||
|
return "webhook"
|
||||||
|
}
|
||||||
|
if receiver.WechatConfigs != nil {
|
||||||
|
return "wechat"
|
||||||
|
}
|
||||||
|
if receiver.MSTeamsConfigs != nil {
|
||||||
|
return "msteams"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ruleDB) GetChannel(id string) (*model.ChannelItem, *model.ApiError) {
|
||||||
|
|
||||||
|
idInt, _ := strconv.Atoi(id)
|
||||||
|
channel := model.ChannelItem{}
|
||||||
|
|
||||||
|
query := "SELECT id, created_at, updated_at, name, type, data data FROM notification_channels WHERE id=?;"
|
||||||
|
|
||||||
|
stmt, err := r.Preparex(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in preparing sql query for GetChannel", zap.Error(err))
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = stmt.Get(&channel, idInt)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in getting channel with id", zap.Int("id", idInt), zap.Error(err))
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &channel, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ruleDB) DeleteChannel(id string) *model.ApiError {
|
||||||
|
|
||||||
|
idInt, _ := strconv.Atoi(id)
|
||||||
|
|
||||||
|
channelToDelete, apiErrorObj := r.GetChannel(id)
|
||||||
|
|
||||||
|
if apiErrorObj != nil {
|
||||||
|
return apiErrorObj
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := r.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
stmt, err := tx.Prepare(`DELETE FROM notification_channels WHERE id=$1;`)
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in preparing statement for INSERT to notification_channels", zap.Error(err))
|
||||||
|
tx.Rollback()
|
||||||
|
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
if _, err := stmt.Exec(idInt); err != nil {
|
||||||
|
zap.L().Error("Error in Executing prepared statement for INSERT to notification_channels", zap.Error(err))
|
||||||
|
tx.Rollback() // return an error too, we may want to wrap them
|
||||||
|
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apiError := r.alertManager.DeleteRoute(channelToDelete.Name)
|
||||||
|
if apiError != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return apiError
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in committing transaction for DELETE command to notification_channels", zap.Error(err))
|
||||||
|
return &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ruleDB) GetChannels() (*[]model.ChannelItem, *model.ApiError) {
|
||||||
|
|
||||||
|
channels := []model.ChannelItem{}
|
||||||
|
|
||||||
|
query := "SELECT id, created_at, updated_at, name, type, data data FROM notification_channels"
|
||||||
|
|
||||||
|
err := r.Select(&channels, query)
|
||||||
|
|
||||||
|
zap.L().Info(query)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in processing sql query", zap.Error(err))
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &channels, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ruleDB) EditChannel(receiver *am.Receiver, id string) (*am.Receiver, *model.ApiError) {
|
||||||
|
|
||||||
|
idInt, _ := strconv.Atoi(id)
|
||||||
|
|
||||||
|
channel, apiErrObj := r.GetChannel(id)
|
||||||
|
|
||||||
|
if apiErrObj != nil {
|
||||||
|
return nil, apiErrObj
|
||||||
|
}
|
||||||
|
if channel.Name != receiver.Name {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: fmt.Errorf("channel name cannot be changed")}
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := r.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_type := getChannelType(receiver)
|
||||||
|
|
||||||
|
receiverString, _ := json.Marshal(receiver)
|
||||||
|
|
||||||
|
{
|
||||||
|
stmt, err := tx.Prepare(`UPDATE notification_channels SET updated_at=$1, type=$2, data=$3 WHERE id=$4;`)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in preparing statement for UPDATE to notification_channels", zap.Error(err))
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
if _, err := stmt.Exec(time.Now(), channel_type, string(receiverString), idInt); err != nil {
|
||||||
|
zap.L().Error("Error in Executing prepared statement for UPDATE to notification_channels", zap.Error(err))
|
||||||
|
tx.Rollback() // return an error too, we may want to wrap them
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apiError := r.alertManager.EditRoute(receiver)
|
||||||
|
if apiError != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, apiError
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in committing transaction for INSERT to notification_channels", zap.Error(err))
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return receiver, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ruleDB) CreateChannel(receiver *am.Receiver) (*am.Receiver, *model.ApiError) {
|
||||||
|
|
||||||
|
channel_type := getChannelType(receiver)
|
||||||
|
|
||||||
|
receiverString, _ := json.Marshal(receiver)
|
||||||
|
|
||||||
|
tx, err := r.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
stmt, err := tx.Prepare(`INSERT INTO notification_channels (created_at, updated_at, name, type, data) VALUES($1,$2,$3,$4,$5);`)
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in preparing statement for INSERT to notification_channels", zap.Error(err))
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
if _, err := stmt.Exec(time.Now(), time.Now(), receiver.Name, channel_type, string(receiverString)); err != nil {
|
||||||
|
zap.L().Error("Error in Executing prepared statement for INSERT to notification_channels", zap.Error(err))
|
||||||
|
tx.Rollback() // return an error too, we may want to wrap them
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apiError := r.alertManager.AddRoute(receiver)
|
||||||
|
if apiError != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return nil, apiError
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit()
|
||||||
|
if err != nil {
|
||||||
|
zap.L().Error("Error in committing transaction for INSERT to notification_channels", zap.Error(err))
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
return receiver, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (r *ruleDB) GetAlertsInfo(ctx context.Context) (*model.AlertsInfo, error) {
|
func (r *ruleDB) GetAlertsInfo(ctx context.Context) (*model.AlertsInfo, error) {
|
||||||
alertsInfo := model.AlertsInfo{}
|
alertsInfo := model.AlertsInfo{}
|
||||||
// fetch alerts from rules db
|
// fetch alerts from rules db
|
||||||
@ -353,5 +585,31 @@ func (r *ruleDB) GetAlertsInfo(ctx context.Context) (*model.AlertsInfo, error) {
|
|||||||
alertsInfo.TotalAlerts = alertsInfo.TotalAlerts + 1
|
alertsInfo.TotalAlerts = alertsInfo.TotalAlerts + 1
|
||||||
}
|
}
|
||||||
alertsInfo.AlertNames = alertNames
|
alertsInfo.AlertNames = alertNames
|
||||||
|
|
||||||
|
channels, _ := r.GetChannels()
|
||||||
|
if channels != nil {
|
||||||
|
alertsInfo.TotalChannels = len(*channels)
|
||||||
|
for _, channel := range *channels {
|
||||||
|
if channel.Type == "slack" {
|
||||||
|
alertsInfo.SlackChannels = alertsInfo.SlackChannels + 1
|
||||||
|
}
|
||||||
|
if channel.Type == "webhook" {
|
||||||
|
alertsInfo.WebHookChannels = alertsInfo.WebHookChannels + 1
|
||||||
|
}
|
||||||
|
if channel.Type == "email" {
|
||||||
|
alertsInfo.EmailChannels = alertsInfo.EmailChannels + 1
|
||||||
|
}
|
||||||
|
if channel.Type == "pagerduty" {
|
||||||
|
alertsInfo.PagerDutyChannels = alertsInfo.PagerDutyChannels + 1
|
||||||
|
}
|
||||||
|
if channel.Type == "opsgenie" {
|
||||||
|
alertsInfo.OpsGenieChannels = alertsInfo.OpsGenieChannels + 1
|
||||||
|
}
|
||||||
|
if channel.Type == "msteams" {
|
||||||
|
alertsInfo.MSTeamsChannels = alertsInfo.MSTeamsChannels + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &alertsInfo, nil
|
return &alertsInfo, nil
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,12 @@ func NewManager(o *ManagerOptions) (*Manager, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
db := NewRuleDB(o.DBConn)
|
amManager, err := am.New()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
db := NewRuleDB(o.DBConn, amManager)
|
||||||
|
|
||||||
telemetry.GetInstance().SetAlertsInfoCallback(db.GetAlertsInfo)
|
telemetry.GetInstance().SetAlertsInfoCallback(db.GetAlertsInfo)
|
||||||
|
|
||||||
|
@ -325,65 +325,46 @@ func createTelemetry() {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
dashboardsInfo, err := telemetry.dashboardsInfoCallback(ctx)
|
dashboardsInfo, err := telemetry.dashboardsInfoCallback(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
channels, err := telemetry.reader.GetChannels()
|
savedViewsInfo, err := telemetry.savedViewsInfoCallback(ctx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, channel := range *channels {
|
dashboardsAlertsData := map[string]interface{}{
|
||||||
switch channel.Type {
|
"totalDashboards": dashboardsInfo.TotalDashboards,
|
||||||
case "slack":
|
"totalDashboardsWithPanelAndName": dashboardsInfo.TotalDashboardsWithPanelAndName,
|
||||||
alertsInfo.SlackChannels++
|
"dashboardNames": dashboardsInfo.DashboardNames,
|
||||||
case "webhook":
|
"alertNames": alertsInfo.AlertNames,
|
||||||
alertsInfo.WebHookChannels++
|
"logsBasedPanels": dashboardsInfo.LogsBasedPanels,
|
||||||
case "pagerduty":
|
"metricBasedPanels": dashboardsInfo.MetricBasedPanels,
|
||||||
alertsInfo.PagerDutyChannels++
|
"tracesBasedPanels": dashboardsInfo.TracesBasedPanels,
|
||||||
case "opsgenie":
|
"dashboardsWithTSV2": dashboardsInfo.QueriesWithTSV2,
|
||||||
alertsInfo.OpsGenieChannels++
|
"dashboardWithLogsChQuery": dashboardsInfo.DashboardsWithLogsChQuery,
|
||||||
case "email":
|
"totalAlerts": alertsInfo.TotalAlerts,
|
||||||
alertsInfo.EmailChannels++
|
"alertsWithTSV2": alertsInfo.AlertsWithTSV2,
|
||||||
case "msteams":
|
"logsBasedAlerts": alertsInfo.LogsBasedAlerts,
|
||||||
alertsInfo.MSTeamsChannels++
|
"metricBasedAlerts": alertsInfo.MetricBasedAlerts,
|
||||||
}
|
"tracesBasedAlerts": alertsInfo.TracesBasedAlerts,
|
||||||
|
"totalChannels": alertsInfo.TotalChannels,
|
||||||
|
"totalSavedViews": savedViewsInfo.TotalSavedViews,
|
||||||
|
"logsSavedViews": savedViewsInfo.LogsSavedViews,
|
||||||
|
"tracesSavedViews": savedViewsInfo.TracesSavedViews,
|
||||||
|
"slackChannels": alertsInfo.SlackChannels,
|
||||||
|
"webHookChannels": alertsInfo.WebHookChannels,
|
||||||
|
"pagerDutyChannels": alertsInfo.PagerDutyChannels,
|
||||||
|
"opsGenieChannels": alertsInfo.OpsGenieChannels,
|
||||||
|
"emailChannels": alertsInfo.EmailChannels,
|
||||||
|
"msteamsChannels": alertsInfo.MSTeamsChannels,
|
||||||
|
"metricsBuilderQueries": alertsInfo.MetricsBuilderQueries,
|
||||||
|
"metricsClickHouseQueries": alertsInfo.MetricsClickHouseQueries,
|
||||||
|
"metricsPrometheusQueries": alertsInfo.MetricsPrometheusQueries,
|
||||||
|
"spanMetricsPrometheusQueries": alertsInfo.SpanMetricsPrometheusQueries,
|
||||||
|
"alertsWithLogsChQuery": alertsInfo.AlertsWithLogsChQuery,
|
||||||
}
|
}
|
||||||
savedViewsInfo, err := telemetry.savedViewsInfoCallback(ctx)
|
// send event only if there are dashboards or alerts or channels
|
||||||
if err == nil {
|
if (dashboardsInfo.TotalDashboards > 0 || alertsInfo.TotalAlerts > 0 || alertsInfo.TotalChannels > 0 || savedViewsInfo.TotalSavedViews > 0) && apiErr == nil {
|
||||||
dashboardsAlertsData := map[string]interface{}{
|
for _, user := range users {
|
||||||
"totalDashboards": dashboardsInfo.TotalDashboards,
|
if user.Email == DEFAULT_CLOUD_EMAIL {
|
||||||
"totalDashboardsWithPanelAndName": dashboardsInfo.TotalDashboardsWithPanelAndName,
|
continue
|
||||||
"dashboardNames": dashboardsInfo.DashboardNames,
|
|
||||||
"alertNames": alertsInfo.AlertNames,
|
|
||||||
"logsBasedPanels": dashboardsInfo.LogsBasedPanels,
|
|
||||||
"metricBasedPanels": dashboardsInfo.MetricBasedPanels,
|
|
||||||
"tracesBasedPanels": dashboardsInfo.TracesBasedPanels,
|
|
||||||
"dashboardsWithTSV2": dashboardsInfo.QueriesWithTSV2,
|
|
||||||
"dashboardWithLogsChQuery": dashboardsInfo.DashboardsWithLogsChQuery,
|
|
||||||
"totalAlerts": alertsInfo.TotalAlerts,
|
|
||||||
"alertsWithTSV2": alertsInfo.AlertsWithTSV2,
|
|
||||||
"logsBasedAlerts": alertsInfo.LogsBasedAlerts,
|
|
||||||
"metricBasedAlerts": alertsInfo.MetricBasedAlerts,
|
|
||||||
"tracesBasedAlerts": alertsInfo.TracesBasedAlerts,
|
|
||||||
"totalChannels": len(*channels),
|
|
||||||
"totalSavedViews": savedViewsInfo.TotalSavedViews,
|
|
||||||
"logsSavedViews": savedViewsInfo.LogsSavedViews,
|
|
||||||
"tracesSavedViews": savedViewsInfo.TracesSavedViews,
|
|
||||||
"slackChannels": alertsInfo.SlackChannels,
|
|
||||||
"webHookChannels": alertsInfo.WebHookChannels,
|
|
||||||
"pagerDutyChannels": alertsInfo.PagerDutyChannels,
|
|
||||||
"opsGenieChannels": alertsInfo.OpsGenieChannels,
|
|
||||||
"emailChannels": alertsInfo.EmailChannels,
|
|
||||||
"msteamsChannels": alertsInfo.MSTeamsChannels,
|
|
||||||
"metricsBuilderQueries": alertsInfo.MetricsBuilderQueries,
|
|
||||||
"metricsClickHouseQueries": alertsInfo.MetricsClickHouseQueries,
|
|
||||||
"metricsPrometheusQueries": alertsInfo.MetricsPrometheusQueries,
|
|
||||||
"spanMetricsPrometheusQueries": alertsInfo.SpanMetricsPrometheusQueries,
|
|
||||||
"alertsWithLogsChQuery": alertsInfo.AlertsWithLogsChQuery,
|
|
||||||
}
|
|
||||||
// send event only if there are dashboards or alerts or channels
|
|
||||||
if (dashboardsInfo.TotalDashboards > 0 || alertsInfo.TotalAlerts > 0 || len(*channels) > 0 || savedViewsInfo.TotalSavedViews > 0) && apiErr == nil {
|
|
||||||
for _, user := range users {
|
|
||||||
if user.Email == DEFAULT_CLOUD_EMAIL {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, dashboardsAlertsData, user.Email, false, false)
|
|
||||||
}
|
}
|
||||||
|
telemetry.SendEvent(TELEMETRY_EVENT_DASHBOARDS_ALERTS, dashboardsAlertsData, user.Email, false, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -467,11 +448,9 @@ func getOutboundIP() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
ipBody, err := io.ReadAll(resp.Body)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ipBody, err := io.ReadAll(resp.Body)
|
ip = ipBody
|
||||||
if err == nil {
|
|
||||||
ip = ipBody
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(ip)
|
return string(ip)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user