mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-30 14:56:15 +00:00
Re-sync the entire SigNoz-derived Go tree to a clean fork of latest SigNoz main (upstream 3e6339019), eliminating the version-skew that broke `go build ./...` (mixed-era packages, ~14 imported-but-absent packages, partial signoz->o11y / clickhouse->datastore rebrands, self-import cycle, duplicate package decls). - pkg/ + cmd/ wholesale replaced with latest SigNoz; imports rewritten github.com/SigNoz/signoz/ -> github.com/hanzoai/o11y/. - Adopt SigNoz's CURRENT structure (resourcefilter->telemetryresourcefilter, integrationtypes->cloudintegrationtypes, roletypes/grammar/times folded in upstream); old paths dropped. - Fork deps repathed to hanzoai + bumped: signoz-otel-collector v0.144.6, clickhouse-go-mock v0.14.1, govaluate v0.1.0; expr-lang/expr => hanzoai/expr v1.17.8 (replace). go.mod reconciled from latest SigNoz; go.sum re-tidied. - ee/ + cmd/enterprise stripped — o11y stays MIT-only; community edition imports no ee packages. - Preserved o11y additions: module path github.com/hanzoai/o11y, mount.go (cloud.Register/zip mount adapter, HIP-0106), NOTICE + LICENSE (SigNoz §4c attribution retained; upstream pkg files are headerless per SigNoz convention). - Reverted o11y cosmetic renames (o11y*/datastore*) and experimental originals (authz/iamauthz, billing, zapreceiver, zapmetricreceiver) to SigNoz canonical to kill the skew; snapshots retained in git history for re-layering. go build ./... = exit 0. go vet clean except benign "unreachable code" in generated ANTLR parser files (inherited from upstream).
173 lines
5.2 KiB
Go
173 lines
5.2 KiB
Go
package opamp
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/open-telemetry/opamp-go/protobufs"
|
|
"github.com/open-telemetry/opamp-go/server"
|
|
"github.com/open-telemetry/opamp-go/server/types"
|
|
|
|
"github.com/hanzoai/o11y/pkg/errors"
|
|
"github.com/hanzoai/o11y/pkg/instrumentation"
|
|
model "github.com/hanzoai/o11y/pkg/query-service/app/opamp/model"
|
|
"github.com/hanzoai/o11y/pkg/valuer"
|
|
)
|
|
|
|
var opAmpServer *Server
|
|
|
|
type Server struct {
|
|
server server.OpAMPServer
|
|
agents *model.Agents
|
|
logger *slog.Logger
|
|
|
|
agentConfigProvider AgentConfigProvider
|
|
|
|
// cleanups to be run when stopping the server
|
|
cleanups []func()
|
|
}
|
|
|
|
const capabilities = protobufs.ServerCapabilities_ServerCapabilities_AcceptsEffectiveConfig |
|
|
protobufs.ServerCapabilities_ServerCapabilities_OffersRemoteConfig |
|
|
protobufs.ServerCapabilities_ServerCapabilities_AcceptsStatus
|
|
|
|
func InitializeServer(
|
|
agents *model.Agents,
|
|
agentConfigProvider AgentConfigProvider,
|
|
instrumentation instrumentation.Instrumentation,
|
|
) *Server {
|
|
if agents == nil {
|
|
agents = &model.AllAgents
|
|
}
|
|
|
|
opAmpServer = &Server{
|
|
agents: agents,
|
|
agentConfigProvider: agentConfigProvider,
|
|
logger: instrumentation.Logger(),
|
|
}
|
|
opAmpServer.server = server.New(wrappedLogger(instrumentation.Logger()))
|
|
return opAmpServer
|
|
}
|
|
|
|
func (srv *Server) Start(listener string) error {
|
|
settings := server.StartSettings{
|
|
Settings: server.Settings{
|
|
Callbacks: types.Callbacks{
|
|
OnConnecting: func(request *http.Request) types.ConnectionResponse {
|
|
return types.ConnectionResponse{
|
|
Accept: true,
|
|
ConnectionCallbacks: types.ConnectionCallbacks{
|
|
OnMessage: srv.OnMessage,
|
|
OnConnectionClose: srv.onDisconnect,
|
|
},
|
|
}
|
|
},
|
|
},
|
|
},
|
|
ListenEndpoint: listener,
|
|
}
|
|
|
|
// This will have to send request to all the agents of all tenants
|
|
unsubscribe := srv.agentConfigProvider.SubscribeToConfigUpdates(func() {
|
|
err := srv.agents.RecommendLatestConfigToAll(srv.agentConfigProvider)
|
|
if err != nil {
|
|
srv.logger.Error(
|
|
"could not roll out latest config recommendation to connected agents", errors.Attr(err),
|
|
)
|
|
}
|
|
})
|
|
srv.cleanups = append(srv.cleanups, unsubscribe)
|
|
|
|
return srv.server.Start(settings)
|
|
}
|
|
|
|
func (srv *Server) Stop() {
|
|
for _, cleanup := range srv.cleanups {
|
|
defer cleanup()
|
|
}
|
|
|
|
_ = srv.server.Stop(context.Background())
|
|
}
|
|
|
|
func (srv *Server) onDisconnect(conn types.Connection) {
|
|
srv.agents.RemoveConnection(conn)
|
|
}
|
|
|
|
// When the agent sends the message for the first time, then we need to know the orgID
|
|
// For the subsequent requests, agents don't send the attributes unless something is changed
|
|
// but we keep them in context mapped which is mapped to the instanceID, so we would know the
|
|
// orgID from the context
|
|
// note :- there can only be 50 agents in the db for a given orgID, we don't have a check in-memory but we delete from the db after insert.
|
|
func (srv *Server) OnMessage(ctx context.Context, conn types.Connection, msg *protobufs.AgentToServer) *protobufs.ServerToAgent {
|
|
agentID, _ := valuer.NewUUIDFromBytes(msg.GetInstanceUid())
|
|
|
|
// find the orgID, if nothing is found keep it empty.
|
|
// the find or create agent will return an error if orgID is empty
|
|
// thus retry will happen
|
|
var orgID valuer.UUID
|
|
orgIDs, err := srv.agents.OrgGetter.ListByOwnedKeyRange(context.Background())
|
|
if err == nil && len(orgIDs) == 1 {
|
|
orgID = orgIDs[0].ID
|
|
}
|
|
|
|
// when a new org is created and the agent is not able to register
|
|
// the changes in pkg/query-service/app/opamp/model/agent.go 270 - 277 takes care that
|
|
// agents sends the effective config when we processStatusUpdate.
|
|
agent, created, err := srv.agents.FindOrCreateAgent(agentID.String(), conn, orgID)
|
|
if err != nil {
|
|
srv.logger.Error("failed to find or create agent", "agent_id", agentID.String(), errors.Attr(err))
|
|
|
|
// Return error response according to OpAMP protocol
|
|
return &protobufs.ServerToAgent{
|
|
InstanceUid: msg.GetInstanceUid(),
|
|
ErrorResponse: &protobufs.ServerErrorResponse{
|
|
Type: protobufs.ServerErrorResponseType_ServerErrorResponseType_Unavailable,
|
|
Details: &protobufs.ServerErrorResponse_RetryInfo{
|
|
RetryInfo: &protobufs.RetryInfo{
|
|
RetryAfterNanoseconds: uint64(5 * time.Second), // minimum recommended retry interval
|
|
},
|
|
},
|
|
},
|
|
// Note: refer to opamp/model/agent.go; look for `Flags` keyword
|
|
// Flags: uint64(protobufs.ServerToAgentFlags_ServerToAgentFlags_ReportFullState),
|
|
}
|
|
}
|
|
|
|
if created {
|
|
agent.CanLB = model.ExtractLbFlag(msg.AgentDescription)
|
|
srv.logger.Debug(
|
|
"new agent added", "can_lb", agent.CanLB,
|
|
"agent_id", agent.AgentID,
|
|
"status", agent.Status,
|
|
)
|
|
}
|
|
|
|
response := &protobufs.ServerToAgent{
|
|
InstanceUid: msg.GetInstanceUid(),
|
|
Capabilities: uint64(capabilities),
|
|
}
|
|
|
|
agent.UpdateStatus(msg, response, srv.agentConfigProvider)
|
|
|
|
return response
|
|
}
|
|
|
|
// global var methods to support singleton pattern. we want to discourage
|
|
// allow multiple servers in one installation
|
|
func Ready() bool {
|
|
if opAmpServer == nil {
|
|
return false
|
|
}
|
|
if opAmpServer.agents.Count() == 0 {
|
|
slog.Warn("no agents available, all agent config requests will be rejected")
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func Subscribe(orgId valuer.UUID, agentId string, hash string, f model.OnChangeCallback) {
|
|
model.ListenToConfigUpdate(orgId, agentId, hash, f)
|
|
}
|