Convert integrations to use slog (#50921)

This commit is contained in:
rosstimothy
2025-01-10 11:08:42 -05:00
committed by GitHub
parent 5b5bab980e
commit cca83feb66
65 changed files with 651 additions and 650 deletions
+34 -15
View File
@@ -33,6 +33,7 @@ import (
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/logger"
pd "github.com/gravitational/teleport/integrations/lib/plugindata"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -118,7 +119,7 @@ func (a *App) run(ctx context.Context) error {
log := logger.Get(ctx)
log.Info("Access list monitor is running")
log.InfoContext(ctx, "Access list monitor is running")
a.job.SetReady(true)
@@ -134,7 +135,7 @@ func (a *App) run(ctx context.Context) error {
}
timer.Reset(jitter(reminderInterval))
case <-ctx.Done():
log.Info("Access list monitor is finished")
log.InfoContext(ctx, "Access list monitor is finished")
return nil
}
}
@@ -146,7 +147,7 @@ func (a *App) run(ctx context.Context) error {
func (a *App) remindIfNecessary(ctx context.Context) error {
log := logger.Get(ctx)
log.Info("Looking for Access List Review reminders")
log.InfoContext(ctx, "Looking for Access List Review reminders")
var nextToken string
var err error
@@ -156,13 +157,14 @@ func (a *App) remindIfNecessary(ctx context.Context) error {
accessLists, nextToken, err = a.apiClient.ListAccessLists(ctx, 0 /* default page size */, nextToken)
if err != nil {
if trace.IsNotImplemented(err) {
log.Errorf("access list endpoint is not implemented on this auth server, so the access list app is ceasing to run.")
log.ErrorContext(ctx, "access list endpoint is not implemented on this auth server, so the access list app is ceasing to run")
return trace.Wrap(err)
} else if trace.IsAccessDenied(err) {
log.Warnf("Slack bot does not have permissions to list access lists. Please add access_list read and list permissions " +
"to the role associated with the Slack bot.")
const msg = "Slack bot does not have permissions to list access lists. Please add access_list read and list permissions " +
"to the role associated with the Slack bot."
log.WarnContext(ctx, msg)
} else {
log.Errorf("error listing access lists: %v", err)
log.ErrorContext(ctx, "error listing access lists", "error", err)
}
break
}
@@ -170,7 +172,10 @@ func (a *App) remindIfNecessary(ctx context.Context) error {
for _, accessList := range accessLists {
recipients, err := a.getRecipientsRequiringReminders(ctx, accessList)
if err != nil {
log.WithError(err).Warnf("Error getting recipients to notify for review due for access list %q", accessList.Spec.Title)
log.WarnContext(ctx, "Error getting recipients to notify for review due for access list",
"error", err,
"access_list", accessList.Spec.Title,
)
continue
}
@@ -195,7 +200,7 @@ func (a *App) remindIfNecessary(ctx context.Context) error {
}
if len(errs) > 0 {
log.WithError(trace.NewAggregate(errs...)).Warn("Error notifying for access list reviews")
log.WarnContext(ctx, "Error notifying for access list reviews", "error", trace.NewAggregate(errs...))
}
return nil
@@ -213,7 +218,10 @@ func (a *App) getRecipientsRequiringReminders(ctx context.Context, accessList *a
// If the current time before the notification start time, skip notifications.
if now.Before(notificationStart) {
log.Debugf("Access list %s is not ready for notifications, notifications start at %s", accessList.GetName(), notificationStart.Format(time.RFC3339))
log.DebugContext(ctx, "Access list is not ready for notifications",
"access_list", accessList.GetName(),
"notification_start_time", notificationStart.Format(time.RFC3339),
)
return nil, nil
}
@@ -255,12 +263,17 @@ func (a *App) fetchRecipients(ctx context.Context, accessList *accesslist.Access
if err != nil {
// TODO(kiosion): Remove in v18; protecting against server not having `GetAccessListOwners` func.
if trace.IsNotImplemented(err) {
log.WithError(err).Warnf("Error getting nested owners for access list '%v', continuing with only explicit owners", accessList.GetName())
log.WarnContext(ctx, "Error getting nested owners for access list, continuing with only explicit owners",
"error", err,
"access_list", accessList.GetName(),
)
for _, owner := range accessList.Spec.Owners {
allOwners = append(allOwners, &owner)
}
} else {
log.WithError(err).Errorf("Error getting owners for access list '%v'", accessList.GetName())
log.ErrorContext(ctx, "Error getting owners for access list",
"error", err,
"access_list", accessList.GetName())
}
}
@@ -270,7 +283,7 @@ func (a *App) fetchRecipients(ctx context.Context, accessList *accesslist.Access
for _, owner := range allOwners {
recipient, err := a.bot.FetchRecipient(ctx, owner.Name)
if err != nil {
log.Debugf("error getting recipient %s", owner.Name)
log.DebugContext(ctx, "error getting recipient", "recipient", owner.Name)
continue
}
allRecipients[owner.Name] = *recipient
@@ -293,7 +306,10 @@ func (a *App) updatePluginDataAndGetRecipientsRequiringReminders(ctx context.Con
// Calculate days from start.
daysFromStart := now.Sub(notificationStart) / oneDay
windowStart = notificationStart.Add(daysFromStart * oneDay)
log.Infof("windowStart: %s, now: %s", windowStart.String(), now.String())
log.InfoContext(ctx, "calculating window start",
"window_start", logutils.StringerAttr(windowStart),
"now", logutils.StringerAttr(now),
)
}
recipients := []common.Recipient{}
@@ -304,7 +320,10 @@ func (a *App) updatePluginDataAndGetRecipientsRequiringReminders(ctx context.Con
// If the notification window is before the last notification date, then this user doesn't need a notification.
if !windowStart.After(lastNotification) {
log.Debugf("User %s has already been notified for access list %s", recipient.Name, accessList.GetName())
log.DebugContext(ctx, "User has already been notified for access list",
"user", recipient.Name,
"access_list", accessList.GetName(),
)
userNotifications[recipient.Name] = lastNotification
continue
}
@@ -151,8 +151,10 @@ func (amrh *RuleHandler) RecipientsFromAccessMonitoringRules(ctx context.Context
for _, rule := range amrh.getAccessMonitoringRules() {
match, err := MatchAccessRequest(rule.Spec.Condition, req)
if err != nil {
log.WithError(err).WithField("rule", rule.Metadata.Name).
Warn("Failed to parse access monitoring notification rule")
log.WarnContext(ctx, "Failed to parse access monitoring notification rule",
"error", err,
"rule", rule.Metadata.Name,
)
}
if !match {
continue
@@ -160,7 +162,7 @@ func (amrh *RuleHandler) RecipientsFromAccessMonitoringRules(ctx context.Context
for _, recipient := range rule.Spec.Notification.Recipients {
rec, err := amrh.fetchRecipientCallback(ctx, recipient)
if err != nil {
log.WithError(err).Warn("Failed to fetch plugin recipients based on Access monitoring rule recipients")
log.WarnContext(ctx, "Failed to fetch plugin recipients based on Access monitoring rule recipients", "error", err)
continue
}
recipientSet.Add(*rec)
@@ -176,8 +178,10 @@ func (amrh *RuleHandler) RawRecipientsFromAccessMonitoringRules(ctx context.Cont
for _, rule := range amrh.getAccessMonitoringRules() {
match, err := MatchAccessRequest(rule.Spec.Condition, req)
if err != nil {
log.WithError(err).WithField("rule", rule.Metadata.Name).
Warn("Failed to parse access monitoring notification rule")
log.WarnContext(ctx, "Failed to parse access monitoring notification rule",
"error", err,
"rule", rule.Metadata.Name,
)
}
if !match {
continue
+44 -32
View File
@@ -21,6 +21,7 @@ package accessrequest
import (
"context"
"fmt"
"log/slog"
"slices"
"strings"
"time"
@@ -36,6 +37,7 @@ import (
"github.com/gravitational/teleport/integrations/lib/logger"
pd "github.com/gravitational/teleport/integrations/lib/plugindata"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -189,16 +191,16 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error {
func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error {
op := event.Type
reqID := event.Resource.GetName()
ctx, _ = logger.WithField(ctx, "request_id", reqID)
ctx, _ = logger.With(ctx, "request_id", reqID)
switch op {
case types.OpPut:
ctx, _ = logger.WithField(ctx, "request_op", "put")
ctx, _ = logger.With(ctx, "request_op", "put")
req, ok := event.Resource.(types.AccessRequest)
if !ok {
return trace.BadParameter("unexpected resource type %T", event.Resource)
}
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
var err error
switch {
@@ -207,21 +209,29 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
case req.GetState().IsResolved():
err = a.onResolvedRequest(ctx, req)
default:
log.WithField("event", event).Warn("Unknown request state")
log.WarnContext(ctx, "Unknown request state",
slog.Group("event",
slog.Any("type", logutils.StringerAttr(event.Type)),
slog.Group("resource",
"kind", event.Resource.GetKind(),
"name", event.Resource.GetName(),
),
),
)
return nil
}
if err != nil {
log.WithError(err).Errorf("Failed to process request")
log.ErrorContext(ctx, "Failed to process request", "error", err)
return trace.Wrap(err)
}
return nil
case types.OpDelete:
ctx, log := logger.WithField(ctx, "request_op", "delete")
ctx, log := logger.With(ctx, "request_op", "delete")
if err := a.onDeletedRequest(ctx, reqID); err != nil {
log.WithError(err).Errorf("Failed to process deleted request")
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
return trace.Wrap(err)
}
return nil
@@ -242,7 +252,7 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
loginsByRole, err := a.getLoginsByRole(ctx, req)
if trace.IsAccessDenied(err) {
log.Warnf("Missing permissions to get logins by role. Please add role.read to the associated role. error: %s", err)
log.WarnContext(ctx, "Missing permissions to get logins by role, please add role.read to the associated role", "error", err)
} else if err != nil {
return trace.Wrap(err)
}
@@ -265,12 +275,12 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
return trace.Wrap(err)
}
} else {
log.Warning("No channel to post")
log.WarnContext(ctx, "No channel to post")
}
// Try to approve the request if user is currently on-call.
if err := a.tryApproveRequest(ctx, reqID, req); err != nil {
log.Warningf("Failed to auto approve request: %v", err)
log.WarnContext(ctx, "Failed to auto approve request", "error", err)
}
case trace.IsAlreadyExists(err):
// The messages were already sent, nothing to do, we can update the reviews
@@ -311,7 +321,7 @@ func (a *App) onResolvedRequest(ctx context.Context, req types.AccessRequest) er
case types.RequestState_PROMOTED:
tag = pd.ResolvedPromoted
default:
logger.Get(ctx).Warningf("Unknown state %v (%s)", state, state.String())
logger.Get(ctx).WarnContext(ctx, "Unknown state", "state", logutils.StringerAttr(state))
return replyErr
}
err := trace.Wrap(a.updateMessages(ctx, req.GetName(), tag, reason, req.GetReviews()))
@@ -330,13 +340,13 @@ func (a *App) broadcastAccessRequestMessages(ctx context.Context, recipients []c
return trace.Wrap(err)
}
for _, data := range sentMessages {
logger.Get(ctx).WithFields(logger.Fields{
"channel_id": data.ChannelID,
"message_id": data.MessageID,
}).Info("Successfully posted messages")
logger.Get(ctx).InfoContext(ctx, "Successfully posted messages",
"channel_id", data.ChannelID,
"message_id", data.MessageID,
)
}
if err != nil {
logger.Get(ctx).WithError(err).Error("Failed to post one or more messages")
logger.Get(ctx).ErrorContext(ctx, "Failed to post one or more messages", "error", err)
}
_, err = a.pluginData.Update(ctx, reqID, func(existing PluginData) (PluginData, error) {
@@ -369,7 +379,7 @@ func (a *App) postReviewReplies(ctx context.Context, reqID string, reqReviews []
return existing, nil
})
if trace.IsAlreadyExists(err) {
logger.Get(ctx).Debug("Failed to post reply: replies are already sent")
logger.Get(ctx).DebugContext(ctx, "Failed to post reply: replies are already sent")
return nil
}
if err != nil {
@@ -383,7 +393,7 @@ func (a *App) postReviewReplies(ctx context.Context, reqID string, reqReviews []
errors := make([]error, 0, len(slice))
for _, data := range pd.SentMessages {
ctx, _ = logger.WithFields(ctx, logger.Fields{"channel_id": data.ChannelID, "message_id": data.MessageID})
ctx, _ = logger.With(ctx, "channel_id", data.ChannelID, "message_id", data.MessageID)
for _, review := range slice {
if err := a.bot.PostReviewReply(ctx, data.ChannelID, data.MessageID, review); err != nil {
errors = append(errors, err)
@@ -425,7 +435,7 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest)
for _, recipient := range recipients {
rec, err := a.bot.FetchRecipient(ctx, recipient)
if err != nil {
log.Warningf("Failed to fetch Opsgenie recipient: %v", err)
log.WarnContext(ctx, "Failed to fetch Opsgenie recipient", "error", err)
continue
}
recipientSet.Add(*rec)
@@ -436,7 +446,7 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest)
validEmailSuggReviewers := []string{}
for _, reviewer := range req.GetSuggestedReviewers() {
if !lib.IsEmail(reviewer) {
log.Warningf("Failed to notify a suggested reviewer: %q does not look like a valid email", reviewer)
log.WarnContext(ctx, "Failed to notify a suggested reviewer with an invalid email address", "reviewer", reviewer)
continue
}
@@ -446,7 +456,7 @@ func (a *App) getMessageRecipients(ctx context.Context, req types.AccessRequest)
for _, rawRecipient := range rawRecipients {
recipient, err := a.bot.FetchRecipient(ctx, rawRecipient)
if err != nil {
log.WithError(err).Warn("Failure when fetching recipient, continuing anyway")
log.WarnContext(ctx, "Failure when fetching recipient, continuing anyway", "error", err)
} else {
recipientSet.Add(*recipient)
}
@@ -476,7 +486,7 @@ func (a *App) updateMessages(ctx context.Context, reqID string, tag pd.Resolutio
return existing, nil
})
if trace.IsNotFound(err) {
log.Debug("Failed to update messages: plugin data is missing")
log.DebugContext(ctx, "Failed to update messages: plugin data is missing")
return nil
}
if trace.IsAlreadyExists(err) {
@@ -485,7 +495,7 @@ func (a *App) updateMessages(ctx context.Context, reqID string, tag pd.Resolutio
"cannot change the resolution tag of an already resolved request, existing: %s, event: %s",
pluginData.ResolutionTag, tag)
}
log.Debug("Request is already resolved, ignoring event")
log.DebugContext(ctx, "Request is already resolved, ignoring event")
return nil
}
if err != nil {
@@ -496,13 +506,17 @@ func (a *App) updateMessages(ctx context.Context, reqID string, tag pd.Resolutio
if err := a.bot.UpdateMessages(ctx, reqID, reqData, sentMessages, reviews); err != nil {
return trace.Wrap(err)
}
log.Infof("Successfully marked request as %s in all messages", tag)
log.InfoContext(ctx, "Marked request with resolution and sent emails!", "resolution", tag)
if err := a.bot.NotifyUser(ctx, reqID, reqData); err != nil && !trace.IsNotImplemented(err) {
return trace.Wrap(err)
}
log.Infof("Successfully notified user %s request marked as %s", reqData.User, tag)
log.InfoContext(ctx, "Successfully notified user",
"user", reqData.User,
"resolution", tag,
)
return nil
}
@@ -545,13 +559,11 @@ func (a *App) getResourceNames(ctx context.Context, req types.AccessRequest) ([]
// tryApproveRequest attempts to automatically approve the access request if the
// user is on call for the configured service/team.
func (a *App) tryApproveRequest(ctx context.Context, reqID string, req types.AccessRequest) error {
log := logger.Get(ctx).
WithField("req_id", reqID).
WithField("user", req.GetUser())
log := logger.Get(ctx).With("req_id", reqID, "user", req.GetUser())
oncallUsers, err := a.bot.FetchOncallUsers(ctx, req)
if trace.IsNotImplemented(err) {
log.Debugf("Skipping auto-approval because %q bot does not support automatic approvals.", a.pluginName)
log.DebugContext(ctx, "Skipping auto-approval because bot does not support automatic approvals", "bot", a.pluginName)
return nil
}
if err != nil {
@@ -559,7 +571,7 @@ func (a *App) tryApproveRequest(ctx context.Context, reqID string, req types.Acc
}
if !slices.Contains(oncallUsers, req.GetUser()) {
log.Debug("Skipping approval because user is not on-call.")
log.DebugContext(ctx, "Skipping approval because user is not on-call")
return nil
}
@@ -573,12 +585,12 @@ func (a *App) tryApproveRequest(ctx context.Context, reqID string, req types.Acc
},
}); err != nil {
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
log.Debug("Request has already been reviewed.")
log.DebugContext(ctx, "Request has already been reviewed")
return nil
}
return trace.Wrap(err)
}
log.Info("Successfully submitted a request approval.")
log.InfoContext(ctx, "Successfully submitted a request approval")
return nil
}
+5 -5
View File
@@ -88,7 +88,7 @@ func (a *BaseApp) WaitReady(ctx context.Context) (bool, error) {
func (a *BaseApp) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
log := logger.Get(ctx)
log.Debug("Checking Teleport server version")
log.DebugContext(ctx, "Checking Teleport server version")
pong, err := a.APIClient.Ping(ctx)
if err != nil {
@@ -156,9 +156,9 @@ func (a *BaseApp) run(ctx context.Context) error {
a.mainJob.SetReady(allOK)
if allOK {
log.Info("Plugin is ready")
log.InfoContext(ctx, "Plugin is ready")
} else {
log.Error("Plugin is not ready")
log.ErrorContext(ctx, "Plugin is not ready")
}
for _, app := range a.apps {
@@ -203,11 +203,11 @@ func (a *BaseApp) init(ctx context.Context) error {
}
}
log.Debug("Starting API health check...")
log.DebugContext(ctx, "Starting API health check")
if err = a.Bot.CheckHealth(ctx); err != nil {
return trace.Wrap(err, "API health check failed")
}
log.Debug("API health check finished ok")
log.DebugContext(ctx, "API health check finished ok")
return nil
}
@@ -20,12 +20,12 @@ package auth
import (
"context"
"log/slog"
"sync"
"time"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/common/auth/oauth"
"github.com/gravitational/teleport/integrations/access/common/auth/storage"
@@ -65,7 +65,7 @@ type RotatedAccessTokenProviderConfig struct {
Refresher oauth.Refresher
Clock clockwork.Clock
Log *logrus.Entry
Log *slog.Logger
}
// CheckAndSetDefaults validates a configuration and sets default values
@@ -87,7 +87,7 @@ func (c *RotatedAccessTokenProviderConfig) CheckAndSetDefaults() error {
c.Clock = clockwork.NewRealClock()
}
if c.Log == nil {
c.Log = logrus.NewEntry(logrus.StandardLogger())
c.Log = slog.Default()
}
return nil
}
@@ -104,7 +104,7 @@ type RotatedAccessTokenProvider struct {
refresher oauth.Refresher
clock clockwork.Clock
log logrus.FieldLogger
log *slog.Logger
lock sync.RWMutex // protects the below fields
creds *storage.Credentials
@@ -153,12 +153,12 @@ func (r *RotatedAccessTokenProvider) RefreshLoop(ctx context.Context) {
timer := r.clock.NewTimer(interval)
defer timer.Stop()
r.log.Infof("Will attempt token refresh in: %s", interval)
r.log.InfoContext(ctx, "Starting token refresh loop", "next_refresh", interval)
for {
select {
case <-ctx.Done():
r.log.Info("Shutting down")
r.log.InfoContext(ctx, "Shutting down")
return
case <-timer.Chan():
creds, _ := r.store.GetCredentials(ctx)
@@ -174,18 +174,21 @@ func (r *RotatedAccessTokenProvider) RefreshLoop(ctx context.Context) {
interval := r.getRefreshInterval(creds)
timer.Reset(interval)
r.log.Infof("Next refresh in: %s", interval)
r.log.InfoContext(ctx, "Refreshed token", "next_refresh", interval)
continue
}
creds, err := r.refresh(ctx)
if err != nil {
r.log.Errorf("Error while refreshing: %s. Will retry after: %s", err, r.retryInterval)
r.log.ErrorContext(ctx, "Error while refreshing token",
"error", err,
"retry_interval", r.retryInterval,
)
timer.Reset(r.retryInterval)
} else {
err := r.store.PutCredentials(ctx, creds)
if err != nil {
r.log.Errorf("Error while storing the refreshed credentials: %s", err)
r.log.ErrorContext(ctx, "Error while storing the refreshed credentials", "error", err)
timer.Reset(r.retryInterval)
continue
}
@@ -196,7 +199,7 @@ func (r *RotatedAccessTokenProvider) RefreshLoop(ctx context.Context) {
interval := r.getRefreshInterval(creds)
timer.Reset(interval)
r.log.Infof("Successfully refreshed credentials. Next refresh in: %s", interval)
r.log.InfoContext(ctx, "Successfully refreshed credentials", "next_refresh", interval)
}
}
}
@@ -20,12 +20,12 @@ package auth
import (
"context"
"log/slog"
"testing"
"time"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport/integrations/access/common/auth/oauth"
@@ -57,9 +57,6 @@ func (s *mockStore) PutCredentials(ctx context.Context, creds *storage.Credentia
}
func TestRotatedAccessTokenProvider(t *testing.T) {
log := logrus.New()
log.Level = logrus.DebugLevel
newProvider := func(ctx context.Context, store storage.Store, refresher oauth.Refresher, clock clockwork.Clock, initialCreds *storage.Credentials) *RotatedAccessTokenProvider {
return &RotatedAccessTokenProvider{
store: store,
@@ -70,7 +67,7 @@ func TestRotatedAccessTokenProvider(t *testing.T) {
tokenBufferInterval: 1 * time.Hour,
creds: initialCreds,
log: log,
log: slog.Default(),
}
}
+1 -1
View File
@@ -162,7 +162,7 @@ func (b Bot) FetchOncallUsers(ctx context.Context, req types.AccessRequest) ([]s
annotationKey := types.TeleportNamespace + types.ReqAnnotationApproveSchedulesLabel
teamNames, err := common.GetNamesFromAnnotations(req, annotationKey)
if err != nil {
log.Debug("Automatic approvals annotation is empty or unspecified.")
log.DebugContext(ctx, "Automatic approvals annotation is empty or unspecified")
return nil, nil
}
+1 -1
View File
@@ -126,7 +126,7 @@ func onAfterDatadogResponse(sink common.StatusSink) resty.ResponseMiddleware {
defer cancel()
if err := sink.Emit(ctx, status); err != nil {
log.WithError(err).Errorf("Error while emitting Datadog Incident Management plugin status: %v", err)
log.ErrorContext(ctx, "Error while emitting Datadog Incident Management plugin status", "error", err)
}
}
@@ -22,6 +22,7 @@ import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"github.com/alecthomas/kingpin/v2"
@@ -67,12 +68,13 @@ func main() {
if err := run(*path, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
}
func run(configPath string, debug bool) error {
ctx := context.Background()
conf, err := datadog.LoadConfig(configPath)
if err != nil {
return trace.Wrap(err)
@@ -86,14 +88,15 @@ func run(configPath string, debug bool) error {
return err
}
if debug {
logger.Standard().Debugf("DEBUG logging enabled")
slog.DebugContext(ctx, "DEBUG logging enabled")
}
app := datadog.NewDatadogApp(conf)
go lib.ServeSignals(app, common.PluginShutdownTimeout)
logger.Standard().Infof("Starting Teleport Access Datadog Incident Management Plugin %s:%s", teleport.Version, teleport.Gitref)
return trace.Wrap(
app.Run(context.Background()),
slog.InfoContext(ctx, "Starting Teleport Access Datadog Incident Management Plugin",
"version", teleport.Version,
"git_ref", teleport.Gitref,
)
return trace.Wrap(app.Run(ctx))
}
@@ -32,7 +32,6 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/datadog"
)
@@ -281,6 +280,6 @@ func (d *FakeDatadog) GetOncallTeams() (map[string][]string, bool) {
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+1 -2
View File
@@ -94,8 +94,7 @@ func emitStatusUpdate(resp *resty.Response, statusSink common.StatusSink) {
if err := statusSink.Emit(ctx, status); err != nil {
logger.Get(resp.Request.Context()).
WithError(err).
Errorf("Error while emitting Discord plugin status: %v", err)
ErrorContext(ctx, "Error while emitting Discord plugin status", "error", err)
}
}
@@ -20,6 +20,7 @@ import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"github.com/alecthomas/kingpin/v2"
@@ -65,12 +66,13 @@ func main() {
if err := run(*path, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
}
func run(configPath string, debug bool) error {
ctx := context.Background()
conf, err := discord.LoadDiscordConfig(configPath)
if err != nil {
return trace.Wrap(err)
@@ -84,14 +86,15 @@ func run(configPath string, debug bool) error {
return trace.Wrap(err)
}
if debug {
logger.Standard().Debugf("DEBUG logging enabled")
slog.DebugContext(ctx, "DEBUG logging enabled")
}
app := discord.NewApp(conf)
go lib.ServeSignals(app, common.PluginShutdownTimeout)
logger.Standard().Infof("Starting Teleport Access Discord Plugin %s:%s", teleport.Version, teleport.Gitref)
return trace.Wrap(
app.Run(context.Background()),
slog.InfoContext(ctx, "Starting Teleport Access Discord Plugin",
"version", teleport.Version,
"git_ref", teleport.Gitref,
)
return trace.Wrap(app.Run(ctx))
}
@@ -32,7 +32,6 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/discord"
)
@@ -188,6 +187,6 @@ func (s *FakeDiscord) CheckMessageUpdateByResponding(ctx context.Context) (disco
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+43 -27
View File
@@ -18,6 +18,7 @@ package email
import (
"context"
"log/slog"
"slices"
"time"
@@ -32,6 +33,7 @@ import (
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -90,7 +92,6 @@ func (a *App) run(ctx context.Context) error {
var err error
log := logger.Get(ctx)
log.Infof("Starting Teleport Access Email Plugin")
if err = a.init(ctx); err != nil {
return trace.Wrap(err)
@@ -137,9 +138,9 @@ func (a *App) run(ctx context.Context) error {
a.mainJob.SetReady(ok)
if ok {
log.Info("Plugin is ready")
log.InfoContext(ctx, "Plugin is ready")
} else {
log.Error("Plugin is not ready")
log.ErrorContext(ctx, "Plugin is not ready")
}
<-watcherJob.Done()
@@ -186,24 +187,24 @@ func (a *App) init(ctx context.Context) error {
},
})
log.Debug("Starting client connection health check...")
log.DebugContext(ctx, "Starting client connection health check")
if err = a.client.CheckHealth(ctx); err != nil {
return trace.Wrap(err, "client connection health check failed")
}
log.Debug("Client connection health check finished ok")
log.DebugContext(ctx, "Client connection health check finished ok")
return nil
}
// checkTeleportVersion checks that Teleport version is not lower than required
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
log := logger.Get(ctx)
log.Debug("Checking Teleport server version")
log.DebugContext(ctx, "Checking Teleport server version")
pong, err := a.apiClient.Ping(ctx)
if err != nil {
if trace.IsNotImplemented(err) {
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
}
log.Error("Unable to get Teleport server version")
log.ErrorContext(ctx, "Unable to get Teleport server version")
return pong, trace.Wrap(err)
}
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
@@ -229,16 +230,16 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
}
op := event.Type
reqID := event.Resource.GetName()
ctx, _ = logger.WithField(ctx, "request_id", reqID)
ctx, _ = logger.With(ctx, "request_id", reqID)
switch op {
case types.OpPut:
ctx, _ = logger.WithField(ctx, "request_op", "put")
ctx, _ = logger.With(ctx, "request_op", "put")
req, ok := event.Resource.(types.AccessRequest)
if !ok {
return trace.Errorf("unexpected resource type %T", event.Resource)
}
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
var err error
switch {
@@ -249,21 +250,31 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
case req.GetState().IsDenied():
err = a.onResolvedRequest(ctx, req)
default:
log.WithField("event", event).Warn("Unknown request state")
log.WarnContext(ctx, "Unknown request state",
slog.Group("event",
slog.Any("type", logutils.StringerAttr(event.Type)),
slog.Group("resource",
"kind", event.Resource.GetKind(),
"name", event.Resource.GetName(),
),
),
)
log.With("event", event).WarnContext(ctx, "Unknown request state")
return nil
}
if err != nil {
log.WithError(err).Errorf("Failed to process request")
log.ErrorContext(ctx, "Failed to process request", "error", err)
return trace.Wrap(err)
}
return nil
case types.OpDelete:
ctx, log := logger.WithField(ctx, "request_op", "delete")
ctx, log := logger.With(ctx, "request_op", "delete")
if err := a.onDeletedRequest(ctx, reqID); err != nil {
log.WithError(err).Errorf("Failed to process deleted request")
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
return trace.Wrap(err)
}
return nil
@@ -292,7 +303,7 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
if isNew {
recipients := a.getRecipients(ctx, req)
if len(recipients) == 0 {
log.Warning("No recipients to send")
log.WarnContext(ctx, "No recipients to send")
return nil
}
@@ -329,7 +340,7 @@ func (a *App) onResolvedRequest(ctx context.Context, req types.AccessRequest) er
case types.RequestState_DENIED:
resolution.Tag = ResolvedDenied
default:
logger.Get(ctx).Warningf("Unknown state %v (%s)", state, state.String())
logger.Get(ctx).WarnContext(ctx, "Unknown state", "state", logutils.StringerAttr(state))
return replyErr
}
err := trace.Wrap(a.sendResolution(ctx, req.GetName(), resolution))
@@ -359,7 +370,7 @@ func (a *App) getRecipients(ctx context.Context, req types.AccessRequest) []comm
rawRecipients := a.conf.RoleToRecipients.GetRawRecipientsFor(req.GetRoles(), req.GetSuggestedReviewers())
for _, rawRecipient := range rawRecipients {
if !lib.IsEmail(rawRecipient) {
log.Warningf("Failed to notify a reviewer: %q does not look like a valid email", rawRecipient)
log.WarnContext(ctx, "Failed to notify a suggested reviewer with an invalid email address", "reviewer", rawRecipient)
continue
}
recipientSet.Add(common.Recipient{
@@ -382,7 +393,7 @@ func (a *App) sendNewThreads(ctx context.Context, recipients []common.Recipient,
logSentThreads(ctx, threadsSent, "new threads")
if err != nil {
logger.Get(ctx).WithError(err).Error("Failed send one or more messages")
logger.Get(ctx).ErrorContext(ctx, "Failed send one or more messages", "error", err)
}
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
@@ -425,7 +436,7 @@ func (a *App) sendReviews(ctx context.Context, reqID string, reqData RequestData
return trace.Wrap(err)
}
if !ok {
logger.Get(ctx).Debug("Failed to post reply: plugin data is missing")
logger.Get(ctx).DebugContext(ctx, "Failed to post reply: plugin data is missing")
return nil
}
reviews := reqReviews[oldCount:]
@@ -439,7 +450,11 @@ func (a *App) sendReviews(ctx context.Context, reqID string, reqData RequestData
if err != nil {
errors = append(errors, err)
}
logger.Get(ctx).Infof("New review for request %v by %v is %v", reqID, review.Author, review.ProposedState.String())
logger.Get(ctx).InfoContext(ctx, "New review for request",
"request_id", reqID,
"author", review.Author,
"state", logutils.StringerAttr(review.ProposedState),
)
logSentThreads(ctx, threadsSent, "new review")
}
@@ -473,7 +488,7 @@ func (a *App) sendResolution(ctx context.Context, reqID string, resolution Resol
return trace.Wrap(err)
}
if !ok {
log.Debug("Failed to update messages: plugin data is missing")
log.DebugContext(ctx, "Failed to update messages: plugin data is missing")
return nil
}
@@ -482,7 +497,7 @@ func (a *App) sendResolution(ctx context.Context, reqID string, resolution Resol
threadsSent, err := a.client.SendResolution(ctx, threads, reqID, reqData)
logSentThreads(ctx, threadsSent, "request resolved")
log.Infof("Marked request as %s and sent emails!", resolution.Tag)
log.InfoContext(ctx, "Marked request with resolution and sent emails", "resolution", resolution.Tag)
if err != nil {
return trace.Wrap(err)
@@ -567,10 +582,11 @@ func (a *App) updatePluginData(ctx context.Context, reqID string, data PluginDat
// logSentThreads logs successfully sent emails
func logSentThreads(ctx context.Context, threads []EmailThread, kind string) {
for _, thread := range threads {
logger.Get(ctx).WithFields(logger.Fields{
"email": thread.Email,
"timestamp": thread.Timestamp,
"message_id": thread.MessageID,
}).Infof("Successfully sent %v!", kind)
logger.Get(ctx).InfoContext(ctx, "Successfully sent",
"email", thread.Email,
"timestamp", thread.Timestamp,
"message_id", thread.MessageID,
"kind", kind,
)
}
}
+6 -6
View File
@@ -61,16 +61,16 @@ func NewClient(ctx context.Context, conf Config, clusterName, webProxyAddr strin
if conf.Mailgun != nil {
mailer = NewMailgunMailer(*conf.Mailgun, conf.StatusSink, conf.Delivery.Sender, clusterName, conf.RoleToRecipients[types.Wildcard])
logger.Get(ctx).WithField("domain", conf.Mailgun.Domain).Info("Using Mailgun as email transport")
logger.Get(ctx).InfoContext(ctx, "Using Mailgun as email transport", "domain", conf.Mailgun.Domain)
}
if conf.SMTP != nil {
mailer = NewSMTPMailer(*conf.SMTP, conf.StatusSink, conf.Delivery.Sender, clusterName)
logger.Get(ctx).WithFields(logger.Fields{
"host": conf.SMTP.Host,
"port": conf.SMTP.Port,
"username": conf.SMTP.Username,
}).Info("Using SMTP as email transport")
logger.Get(ctx).InfoContext(ctx, "Using SMTP as email transport",
"host", conf.SMTP.Host,
"port", conf.SMTP.Port,
"username", conf.SMTP.Username,
)
}
return Client{
@@ -20,6 +20,7 @@ import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"github.com/alecthomas/kingpin/v2"
@@ -65,12 +66,13 @@ func main() {
if err := run(*path, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
}
func run(configPath string, debug bool) error {
ctx := context.Background()
conf, err := email.LoadConfig(configPath)
if err != nil {
return trace.Wrap(err)
@@ -84,11 +86,11 @@ func run(configPath string, debug bool) error {
return err
}
if debug {
logger.Standard().Debugf("DEBUG logging enabled")
slog.DebugContext(ctx, "DEBUG logging enabled")
}
if conf.Delivery.Recipients != nil {
logger.Standard().Warn("The delivery.recipients config option is deprecated, set role_to_recipients[\"*\"] instead for the same functionality")
slog.WarnContext(ctx, "The delivery.recipients config option is deprecated, set role_to_recipients[\"*\"] instead for the same functionality")
}
app, err := email.NewApp(*conf)
@@ -98,8 +100,9 @@ func run(configPath string, debug bool) error {
go lib.ServeSignals(app, common.PluginShutdownTimeout)
logger.Standard().Infof("Starting Teleport Access Email Plugin %s:%s", teleport.Version, teleport.Gitref)
return trace.Wrap(
app.Run(context.Background()),
slog.InfoContext(ctx, "Starting Teleport Access Email Plugin",
"version", teleport.Version,
"git_ref", teleport.Gitref,
)
return trace.Wrap(app.Run(ctx))
}
+3 -3
View File
@@ -114,7 +114,7 @@ func (m *SMTPMailer) CheckHealth(ctx context.Context) error {
return trace.Wrap(err)
}
if err := client.Close(); err != nil {
log.Debug("Failed to close client connection after health check")
log.DebugContext(ctx, "Failed to close client connection after health check")
}
return nil
}
@@ -191,7 +191,7 @@ func (m *SMTPMailer) emitStatus(ctx context.Context, statusErr error) {
code = http.StatusInternalServerError
}
if err := m.sink.Emit(ctx, common.StatusFromStatusCode(code)); err != nil {
log.WithError(err).Error("Error while emitting Email plugin status")
log.ErrorContext(ctx, "Error while emitting Email plugin status", "error", err)
}
}
@@ -252,7 +252,7 @@ func (t *statusSinkTransport) RoundTrip(req *http.Request) (*http.Response, erro
status := common.StatusFromStatusCode(resp.StatusCode)
if err := t.sink.Emit(ctx, status); err != nil {
log.WithError(err).Error("Error while emitting Email plugin status")
log.ErrorContext(ctx, "Error while emitting Email plugin status", "error", err)
}
}
return resp, nil
@@ -24,7 +24,6 @@ import (
"github.com/google/uuid"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
)
const (
@@ -58,7 +57,8 @@ func newMockMailgunServer(concurrency int) *mockMailgunServer {
s := httptest.NewUnstartedServer(func(mg *mockMailgunServer) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(multipartFormBufSize); err != nil {
log.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
id := uuid.New().String()
+60 -49
View File
@@ -21,6 +21,7 @@ package jira
import (
"context"
"fmt"
"log/slog"
"net/url"
"regexp"
"strings"
@@ -40,6 +41,7 @@ import (
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -125,7 +127,6 @@ func (a *App) run(ctx context.Context) error {
var err error
log := logger.Get(ctx)
log.Infof("Starting Teleport Jira Plugin")
if err = a.init(ctx); err != nil {
return trace.Wrap(err)
@@ -164,9 +165,9 @@ func (a *App) run(ctx context.Context) error {
ok := (a.webhookSrv == nil || httpOk) && watcherOk
a.mainJob.SetReady(ok)
if ok {
log.Info("Plugin is ready")
log.InfoContext(ctx, "Plugin is ready")
} else {
log.Error("Plugin is not ready")
log.ErrorContext(ctx, "Plugin is not ready")
}
if httpJob != nil {
@@ -205,11 +206,11 @@ func (a *App) init(ctx context.Context) error {
return trace.Wrap(err)
}
log.Debug("Starting Jira API health check...")
log.DebugContext(ctx, "Starting Jira API health check")
if err = a.jira.HealthCheck(ctx); err != nil {
return trace.Wrap(err, "api health check failed")
}
log.Debug("Jira API health check finished ok")
log.DebugContext(ctx, "Jira API health check finished ok")
if !a.conf.DisableWebhook {
webhookSrv, err := NewWebhookServer(a.conf.HTTP, a.onJiraWebhook)
@@ -227,13 +228,13 @@ func (a *App) init(ctx context.Context) error {
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
log := logger.Get(ctx)
log.Debug("Checking Teleport server version")
log.DebugContext(ctx, "Checking Teleport server version")
pong, err := a.teleport.Ping(ctx)
if err != nil {
if trace.IsNotImplemented(err) {
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
}
log.Error("Unable to get Teleport server version")
log.ErrorContext(ctx, "Unable to get Teleport server version")
return pong, trace.Wrap(err)
}
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
@@ -246,17 +247,17 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error {
}
op := event.Type
reqID := event.Resource.GetName()
ctx, _ = logger.WithField(ctx, "request_id", reqID)
ctx, _ = logger.With(ctx, "request_id", reqID)
switch op {
case types.OpPut:
ctx, _ = logger.WithField(ctx, "request_op", "put")
ctx, _ = logger.With(ctx, "request_op", "put")
req, ok := event.Resource.(types.AccessRequest)
if !ok {
return trace.Errorf("unexpected resource type %T", event.Resource)
}
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
log.Debug("Processing watcher event")
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
log.DebugContext(ctx, "Processing watcher event")
var err error
switch {
@@ -265,21 +266,29 @@ func (a *App) onWatcherEvent(ctx context.Context, event types.Event) error {
case req.GetState().IsResolved():
err = a.onResolvedRequest(ctx, req)
default:
log.WithField("event", event).Warn("Unknown request state")
log.WarnContext(ctx, "Unknown request state",
slog.Group("event",
slog.Any("type", logutils.StringerAttr(event.Type)),
slog.Group("resource",
"kind", event.Resource.GetKind(),
"name", event.Resource.GetName(),
),
),
)
return nil
}
if err != nil {
log.WithError(err).Error("Failed to process request")
log.ErrorContext(ctx, "Failed to process request", "error", err)
return trace.Wrap(err)
}
return nil
case types.OpDelete:
ctx, log := logger.WithField(ctx, "request_op", "delete")
ctx, log := logger.With(ctx, "request_op", "delete")
if err := a.onDeletedRequest(ctx, reqID); err != nil {
log.WithError(err).Errorf("Failed to process deleted request")
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
return trace.Wrap(err)
}
return nil
@@ -299,10 +308,11 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
return nil
}
ctx, log := logger.WithFields(ctx, logger.Fields{
"jira_issue_id": webhook.Issue.ID,
})
log.Debugf("Processing incoming webhook event %q with type %q", webhookEvent, issueEventTypeName)
ctx, log := logger.With(ctx, "jira_issue_id", webhook.Issue.ID)
log.DebugContext(ctx, "Processing incoming webhook event",
"event", webhookEvent,
"event_type", issueEventTypeName,
)
if webhook.Issue == nil {
return trace.Errorf("got webhook without issue info")
@@ -333,20 +343,20 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
if statusName == "" {
return trace.Errorf("getting Jira issue status: %w", err)
}
log.Warnf("Using most recent successful getIssue response: %v", err)
log.WarnContext(ctx, "Using most recent successful getIssue response", "error", err)
}
ctx, log = logger.WithFields(ctx, logger.Fields{
"jira_issue_id": issue.ID,
"jira_issue_key": issue.Key,
})
ctx, log = logger.With(ctx,
"jira_issue_id", issue.ID,
"jira_issue_key", issue.Key,
)
switch {
case statusName == "pending":
log.Debug("Issue has pending status, ignoring it")
log.DebugContext(ctx, "Issue has pending status, ignoring it")
return nil
case statusName == "expired":
log.Debug("Issue has expired status, ignoring it")
log.DebugContext(ctx, "Issue has expired status, ignoring it")
return nil
case statusName != "approved" && statusName != "denied":
return trace.BadParameter("unknown Jira status %s", statusName)
@@ -357,11 +367,11 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
return trace.Wrap(err)
}
if reqID == "" {
log.Debugf("Missing %q issue property", RequestIDPropertyKey)
log.DebugContext(ctx, "Missing teleportAccessRequestId issue property")
return nil
}
ctx, log = logger.WithField(ctx, "request_id", reqID)
ctx, log = logger.With(ctx, "request_id", reqID)
reqs, err := a.teleport.GetAccessRequests(ctx, types.AccessRequestFilter{ID: reqID})
if err != nil {
@@ -382,8 +392,9 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
return trace.Errorf("plugin data is blank")
}
if pluginData.IssueID != issue.ID {
log.WithField("plugin_data_issue_id", pluginData.IssueID).
Debug("plugin_data.issue_id does not match issue.id")
log.DebugContext(ctx, "plugin_data.issue_id does not match issue.id",
"plugin_data_issue_id", pluginData.IssueID,
)
return trace.Errorf("issue_id from request's plugin_data does not match")
}
@@ -406,17 +417,17 @@ func (a *App) onJiraWebhook(_ context.Context, webhook Webhook) error {
author, reason, err := a.loadResolutionInfo(ctx, issue, statusName)
if err != nil {
log.WithError(err).Error("Failed to load resolution info from the issue history")
log.ErrorContext(ctx, "Failed to load resolution info from the issue history", "error", err)
}
resolution.Reason = reason
ctx, _ = logger.WithFields(ctx, logger.Fields{
"jira_user_email": author.EmailAddress,
"jira_user_name": author.DisplayName,
"request_user": req.GetUser(),
"request_roles": req.GetRoles(),
"reason": reason,
})
ctx, _ = logger.With(ctx,
"jira_user_email", author.EmailAddress,
"jira_user_name", author.DisplayName,
"request_user", req.GetUser(),
"request_roles", req.GetRoles(),
"reason", reason,
)
if err := a.resolveRequest(ctx, reqID, author.EmailAddress, resolution); err != nil {
return trace.Wrap(err)
}
@@ -498,11 +509,11 @@ func (a *App) createIssue(ctx context.Context, reqID string, reqData RequestData
return trace.Wrap(err)
}
ctx, log := logger.WithFields(ctx, logger.Fields{
"jira_issue_id": data.IssueID,
"jira_issue_key": data.IssueKey,
})
log.Info("Jira Issue created")
ctx, log := logger.With(ctx,
"jira_issue_id", data.IssueID,
"jira_issue_key", data.IssueKey,
)
log.InfoContext(ctx, "Jira Issue created")
// Save jira issue info in plugin data.
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
@@ -551,11 +562,11 @@ func (a *App) addReviewComments(ctx context.Context, reqID string, reqReviews []
}
if !ok {
if issueID == "" {
logger.Get(ctx).Debug("Failed to add the comment: plugin data is blank")
logger.Get(ctx).DebugContext(ctx, "Failed to add the comment: plugin data is blank")
}
return nil
}
ctx, _ = logger.WithField(ctx, "jira_issue_id", issueID)
ctx, _ = logger.With(ctx, "jira_issue_id", issueID)
slice := reqReviews[oldCount:]
if len(slice) == 0 {
@@ -621,7 +632,7 @@ func (a *App) resolveRequest(ctx context.Context, reqID string, userEmail string
return trace.Wrap(err)
}
logger.Get(ctx).Infof("Jira user %s the request", resolution.Tag)
logger.Get(ctx).InfoContext(ctx, "Jira user processed the request", "resolution", resolution.Tag)
return nil
}
@@ -658,18 +669,18 @@ func (a *App) resolveIssue(ctx context.Context, reqID string, resolution Resolut
}
if !ok {
if issueID == "" {
logger.Get(ctx).Debug("Failed to resolve the issue: plugin data is blank")
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the issue: plugin data is blank")
}
// Either plugin data is missing or issue is already resolved by us, just quit.
return nil
}
ctx, log := logger.WithField(ctx, "jira_issue_id", issueID)
ctx, log := logger.With(ctx, "jira_issue_id", issueID)
if err := a.jira.ResolveIssue(ctx, issueID, resolution); err != nil {
return trace.Wrap(err)
}
log.Info("Successfully resolved the issue")
log.InfoContext(ctx, "Successfully resolved the issue")
return nil
}
+9 -6
View File
@@ -125,7 +125,7 @@ func NewJiraClient(conf JiraConfig, clusterName, teleportProxyAddr string, statu
defer cancel()
if err := statusSink.Emit(ctx, status); err != nil {
log.WithError(err).Errorf("Error while emitting Jira plugin status: %v", err)
log.ErrorContext(ctx, "Error while emitting Jira plugin status", "error", err)
}
}
@@ -199,7 +199,7 @@ func (j *Jira) HealthCheck(ctx context.Context) error {
}
}
log.Debug("Checking out Jira project...")
log.DebugContext(ctx, "Checking out Jira project")
var project Project
_, err = j.client.NewRequest().
SetContext(ctx).
@@ -209,9 +209,12 @@ func (j *Jira) HealthCheck(ctx context.Context) error {
if err != nil {
return trace.Wrap(err)
}
log.Debugf("Found project %q named %q", project.Key, project.Name)
log.DebugContext(ctx, "Found Jira project",
"project", project.Key,
"project_name", project.Name,
)
log.Debug("Checking out Jira project permissions...")
log.DebugContext(ctx, "Checking out Jira project permissions")
queryOptions, err := query.Values(GetMyPermissionsQueryOptions{
ProjectKey: j.project,
Permissions: jiraRequiredPermissions,
@@ -433,7 +436,7 @@ func (j *Jira) ResolveIssue(ctx context.Context, issueID string, resolution Reso
if err2 := trace.Wrap(j.TransitionIssue(ctx, issue.ID, transition.ID)); err2 != nil {
return trace.NewAggregate(err1, err2)
}
logger.Get(ctx).Debugf("Successfully moved the issue to the status %q", toStatus)
logger.Get(ctx).DebugContext(ctx, "Successfully moved the issue to the target status", "target_status", toStatus)
return trace.Wrap(err1)
}
@@ -457,7 +460,7 @@ func (j *Jira) AddResolutionComment(ctx context.Context, id string, resolution R
SetBody(CommentInput{Body: builder.String()}).
Post("rest/api/2/issue/{issueID}/comment")
if err == nil {
logger.Get(ctx).Debug("Successfully added a resolution comment to the issue")
logger.Get(ctx).DebugContext(ctx, "Successfully added a resolution comment to the issue")
}
return trace.Wrap(err)
}
@@ -20,6 +20,7 @@ import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"github.com/alecthomas/kingpin/v2"
@@ -72,12 +73,13 @@ func main() {
if err := run(*path, *insecure, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
}
func run(configPath string, insecure bool, debug bool) error {
ctx := context.Background()
conf, err := jira.LoadConfig(configPath)
if err != nil {
return trace.Wrap(err)
@@ -91,7 +93,7 @@ func run(configPath string, insecure bool, debug bool) error {
return err
}
if debug {
logger.Standard().Debugf("DEBUG logging enabled")
slog.DebugContext(ctx, "DEBUG logging enabled")
}
conf.HTTP.Insecure = insecure
@@ -102,8 +104,9 @@ func run(configPath string, insecure bool, debug bool) error {
go lib.ServeSignals(app, common.PluginShutdownTimeout)
logger.Standard().Infof("Starting Teleport Access Jira Plugin %s:%s", teleport.Version, teleport.Gitref)
return trace.Wrap(
app.Run(context.Background()),
slog.InfoContext(ctx, "Starting Teleport Access Jira Plugin",
"version", teleport.Version,
"git_ref", teleport.Gitref,
)
return trace.Wrap(app.Run(ctx))
}
@@ -30,7 +30,6 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/jira"
)
@@ -304,6 +303,6 @@ func (s *FakeJira) CheckIssueTransition(ctx context.Context) (jira.Issue, error)
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+1 -1
View File
@@ -721,7 +721,7 @@ func (s *JiraSuiteOSS) TestRace() {
defer cancel()
var lastErr error
for {
logger.Get(ctx).Infof("Trying to approve issue %q", issue.Key)
logger.Get(ctx).InfoContext(ctx, "Trying to approve issue", "issue_key", issue.Key)
resp, err := s.postWebhook(ctx, s.webhookURL.String(), issue.ID, "Approved")
if err != nil {
if lib.IsDeadline(err) {
+8 -6
View File
@@ -105,29 +105,31 @@ func (s *WebhookServer) processWebhook(rw http.ResponseWriter, r *http.Request,
defer cancel()
httpRequestID := fmt.Sprintf("%v-%v", time.Now().Unix(), atomic.AddUint64(&s.counter, 1))
ctx, log := logger.WithField(ctx, "jira_http_id", httpRequestID)
ctx, log := logger.With(ctx, "jira_http_id", httpRequestID)
var webhook Webhook
body, err := io.ReadAll(io.LimitReader(r.Body, jiraWebhookPayloadLimit+1))
if err != nil {
log.WithError(err).Error("Failed to read webhook payload")
log.ErrorContext(ctx, "Failed to read webhook payload", "error", err)
http.Error(rw, "", http.StatusInternalServerError)
return
}
if len(body) > jiraWebhookPayloadLimit {
log.Error("Received a webhook larger than %d bytes", jiraWebhookPayloadLimit)
log.ErrorContext(ctx, "Received a webhook with a payload that exceeded the limit",
"payload_size", len(body),
"payload_size_limit", jiraWebhookPayloadLimit,
)
http.Error(rw, "", http.StatusRequestEntityTooLarge)
}
if err = json.Unmarshal(body, &webhook); err != nil {
log.WithError(err).Error("Failed to parse webhook payload")
log.ErrorContext(ctx, "Failed to parse webhook payload", "error", err)
http.Error(rw, "", http.StatusBadRequest)
return
}
if err = s.onWebhook(ctx, webhook); err != nil {
log.WithError(err).Error("Failed to process webhook")
log.Debugf("%v", trace.DebugReport(err))
log.ErrorContext(ctx, "Failed to process webhook", "error", err)
var code int
switch {
case lib.IsCanceled(err) || lib.IsDeadline(err):
+10 -10
View File
@@ -150,7 +150,7 @@ func NewBot(conf Config, clusterName, webProxyAddr string) (Bot, error) {
ctx, cancel := context.WithTimeout(context.Background(), mmStatusEmitTimeout)
defer cancel()
if err := sink.Emit(ctx, status); err != nil {
log.Errorf("Error while emitting plugin status: %v", err)
log.ErrorContext(ctx, "Error while emitting plugin status", "error", err)
}
}()
@@ -463,14 +463,14 @@ func (b Bot) buildPostText(reqID string, reqData pd.AccessRequestData) (string,
}
func (b Bot) tryLookupDirectChannel(ctx context.Context, userEmail string) string {
log := logger.Get(ctx).WithField("mm_user_email", userEmail)
log := logger.Get(ctx).With("mm_user_email", userEmail)
channel, err := b.LookupDirectChannel(ctx, userEmail)
if err != nil {
var errResult *ErrorResult
if errors.As(trace.Unwrap(err), &errResult) {
log.Warningf("Failed to lookup direct channel info: %q", errResult.Message)
log.WarnContext(ctx, "Failed to lookup direct channel info", "error", errResult.Message)
} else {
log.WithError(err).Error("Failed to lookup direct channel info")
log.ErrorContext(ctx, "Failed to lookup direct channel info", "error", err)
}
return ""
}
@@ -478,17 +478,17 @@ func (b Bot) tryLookupDirectChannel(ctx context.Context, userEmail string) strin
}
func (b Bot) tryLookupChannel(ctx context.Context, team, name string) string {
log := logger.Get(ctx).WithFields(logger.Fields{
"mm_team": team,
"mm_channel": name,
})
log := logger.Get(ctx).With(
"mm_team", team,
"mm_channel", name,
)
channel, err := b.LookupChannel(ctx, team, name)
if err != nil {
var errResult *ErrorResult
if errors.As(trace.Unwrap(err), &errResult) {
log.Warningf("Failed to lookup channel info: %q", errResult.Message)
log.WarnContext(ctx, "Failed to lookup channel info", "error", errResult.Message)
} else {
log.WithError(err).Error("Failed to lookup channel info")
log.ErrorContext(ctx, "Failed to lookup channel info", "error", err)
}
return ""
}
@@ -20,6 +20,7 @@ import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"github.com/alecthomas/kingpin/v2"
@@ -65,12 +66,13 @@ func main() {
if err := run(*path, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
}
func run(configPath string, debug bool) error {
ctx := context.Background()
conf, err := mattermost.LoadConfig(configPath)
if err != nil {
return trace.Wrap(err)
@@ -84,14 +86,15 @@ func run(configPath string, debug bool) error {
return err
}
if debug {
logger.Standard().Debugf("DEBUG logging enabled")
slog.DebugContext(ctx, "DEBUG logging enabled")
}
app := mattermost.NewMattermostApp(conf)
go lib.ServeSignals(app, common.PluginShutdownTimeout)
logger.Standard().Infof("Starting Teleport Access Mattermost Plugin %s:%s", teleport.Version, teleport.Gitref)
return trace.Wrap(
app.Run(context.Background()),
slog.InfoContext(ctx, "Starting Teleport Access Mattermost Plugin",
"version", teleport.Version,
"git_ref", teleport.Gitref,
)
return trace.Wrap(app.Run(ctx))
}
@@ -31,7 +31,6 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/mattermost"
)
@@ -387,6 +386,6 @@ func (s *FakeMattermost) CheckPostUpdate(ctx context.Context) (mattermost.Post,
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+1 -6
View File
@@ -62,14 +62,9 @@ type App struct {
// NewApp initializes a new teleport-msteams app and returns it.
func NewApp(conf Config) (*App, error) {
log, err := conf.Log.NewSLogLogger()
if err != nil {
return nil, trace.Wrap(err)
}
app := &App{
conf: conf,
log: log.With("plugin", pluginName),
log: slog.With("plugin", pluginName),
}
app.mainJob = lib.NewServiceJob(app.run)
+1 -2
View File
@@ -30,7 +30,6 @@ import (
"github.com/gravitational/teleport/integrations/access/common"
"github.com/gravitational/teleport/integrations/access/msteams/msapi"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/plugindata"
)
@@ -469,7 +468,7 @@ func (b *Bot) CheckHealth(ctx context.Context) error {
Code: status,
ErrorMessage: message,
}); err != nil {
logger.Get(ctx).Errorf("Error while emitting ms teams plugin status: %v", err)
b.log.ErrorContext(ctx, "Error while emitting ms teams plugin status", "error", err)
}
}
return trace.Wrap(err)
@@ -16,6 +16,7 @@ package main
import (
"context"
"log/slog"
"os"
"time"
@@ -99,7 +100,7 @@ func main() {
if err := run(*startConfigPath, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
@@ -30,7 +30,6 @@ import (
"github.com/google/uuid"
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/msteams/msapi"
)
@@ -326,6 +325,6 @@ func (s *FakeTeams) CheckMessageUpdate(ctx context.Context) (Msg, error) {
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+10 -7
View File
@@ -18,7 +18,8 @@ import (
"context"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/lib/logger"
)
func Uninstall(ctx context.Context, configPath string) error {
@@ -26,11 +27,13 @@ func Uninstall(ctx context.Context, configPath string) error {
if err != nil {
return trace.Wrap(err)
}
err = checkApp(ctx, b)
if err != nil {
if err := checkApp(ctx, b); err != nil {
return trace.Wrap(err)
}
log := logger.Get(ctx)
var errs []error
for _, recipient := range c.Recipients.GetAllRawRecipients() {
_, isChannel := b.checkChannelURL(recipient)
@@ -38,11 +41,11 @@ func Uninstall(ctx context.Context, configPath string) error {
errs = append(errs, b.UninstallAppForUser(ctx, recipient))
}
}
err = trace.NewAggregate(errs...)
if err != nil {
log.Errorln("The following error(s) happened when uninstalling the Teams App:")
if trace.NewAggregate(errs...) != nil {
log.ErrorContext(ctx, "Encountered error(s) when uninstalling the Teams App", "error", err)
return err
}
log.Info("Successfully uninstalled app for all recipients")
log.InfoContext(ctx, "Successfully uninstalled app for all recipients")
return nil
}
+2 -5
View File
@@ -17,6 +17,7 @@ package msteams
import (
"context"
"fmt"
"log/slog"
"time"
cards "github.com/DanielTitkov/go-adaptive-cards"
@@ -142,11 +143,7 @@ func loadConfig(configPath string) (*Bot, *Config, error) {
fmt.Printf(" - Checking application %v status...\n", c.MSAPI.TeamsAppID)
log, err := c.Log.NewSLogLogger()
if err != nil {
return nil, nil, trace.Wrap(err)
}
b, err := NewBot(c, "local", "", log)
b, err := NewBot(c, "local", "", slog.Default())
if err != nil {
return nil, nil, trace.Wrap(err)
}
+37 -27
View File
@@ -22,6 +22,7 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
"time"
@@ -39,6 +40,7 @@ import (
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -115,7 +117,7 @@ func (a *App) run(ctx context.Context) error {
var err error
log := logger.Get(ctx)
log.Infof("Starting Teleport Access Opsgenie Plugin")
log.InfoContext(ctx, "Starting Teleport Access Opsgenie Plugin")
if err = a.init(ctx); err != nil {
return trace.Wrap(err)
@@ -147,9 +149,9 @@ func (a *App) run(ctx context.Context) error {
a.mainJob.SetReady(ok)
if ok {
log.Info("Plugin is ready")
log.InfoContext(ctx, "Plugin is ready")
} else {
log.Error("Plugin is not ready")
log.ErrorContext(ctx, "Plugin is not ready")
}
<-watcherJob.Done()
@@ -177,24 +179,24 @@ func (a *App) init(ctx context.Context) error {
}
log := logger.Get(ctx)
log.Debug("Starting API health check...")
log.DebugContext(ctx, "Starting API health check")
if err = a.opsgenie.CheckHealth(ctx); err != nil {
return trace.Wrap(err, "API health check failed")
}
log.Debug("API health check finished ok")
log.DebugContext(ctx, "API health check finished ok")
return nil
}
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
log := logger.Get(ctx)
log.Debug("Checking Teleport server version")
log.DebugContext(ctx, "Checking Teleport server version")
pong, err := a.teleport.Ping(ctx)
if err != nil {
if trace.IsNotImplemented(err) {
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
}
log.Error("Unable to get Teleport server version")
log.ErrorContext(ctx, "Unable to get Teleport server version")
return pong, trace.Wrap(err)
}
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
@@ -219,16 +221,16 @@ func (a *App) handleAcessRequest(ctx context.Context, event types.Event) error {
}
op := event.Type
reqID := event.Resource.GetName()
ctx, _ = logger.WithField(ctx, "request_id", reqID)
ctx, _ = logger.With(ctx, "request_id", reqID)
switch op {
case types.OpPut:
ctx, _ = logger.WithField(ctx, "request_op", "put")
ctx, _ = logger.With(ctx, "request_op", "put")
req, ok := event.Resource.(types.AccessRequest)
if !ok {
return trace.Errorf("unexpected resource type %T", event.Resource)
}
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
var err error
switch {
@@ -237,21 +239,29 @@ func (a *App) handleAcessRequest(ctx context.Context, event types.Event) error {
case req.GetState().IsResolved():
err = a.onResolvedRequest(ctx, req)
default:
log.WithField("event", event).Warn("Unknown request state")
log.WarnContext(ctx, "Unknown request state",
slog.Group("event",
slog.Any("type", logutils.StringerAttr(event.Type)),
slog.Group("resource",
"kind", event.Resource.GetKind(),
"name", event.Resource.GetName(),
),
),
)
return nil
}
if err != nil {
log.WithError(err).Error("Failed to process request")
log.ErrorContext(ctx, "Failed to process request", "error", err)
return trace.Wrap(err)
}
return nil
case types.OpDelete:
ctx, log := logger.WithField(ctx, "request_op", "delete")
ctx, log := logger.With(ctx, "request_op", "delete")
if err := a.onDeletedRequest(ctx, reqID); err != nil {
log.WithError(err).Error("Failed to process deleted request")
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
return trace.Wrap(err)
}
return nil
@@ -310,13 +320,13 @@ func (a *App) getNotifySchedulesAndTeams(ctx context.Context, req types.AccessRe
scheduleAnnotationKey := types.TeleportNamespace + types.ReqAnnotationNotifySchedulesLabel
schedules, err = common.GetNamesFromAnnotations(req, scheduleAnnotationKey)
if err != nil {
log.Debugf("No schedules to notify in %s", scheduleAnnotationKey)
log.DebugContext(ctx, "No schedules to notify", "schedule", scheduleAnnotationKey)
}
teamAnnotationKey := types.TeleportNamespace + types.ReqAnnotationTeamsLabel
teams, err = common.GetNamesFromAnnotations(req, teamAnnotationKey)
if err != nil {
log.Debugf("No teams to notify in %s", teamAnnotationKey)
log.DebugContext(ctx, "No teams to notify", "teams", teamAnnotationKey)
}
if len(schedules) == 0 && len(teams) == 0 {
@@ -336,7 +346,7 @@ func (a *App) tryNotifyService(ctx context.Context, req types.AccessRequest) (bo
recipientSchedules, recipientTeams, err := a.getMessageRecipients(ctx, req)
if err != nil {
log.Debugf("Skipping the notification: %s", err)
log.DebugContext(ctx, "Skipping notification", "error", err)
return false, trace.Wrap(errMissingAnnotation)
}
@@ -434,8 +444,8 @@ func (a *App) createAlert(ctx context.Context, reqID string, reqData RequestData
if err != nil {
return trace.Wrap(err)
}
ctx, log := logger.WithField(ctx, "opsgenie_alert_id", data.AlertID)
log.Info("Successfully created Opsgenie alert")
ctx, log := logger.With(ctx, "opsgenie_alert_id", data.AlertID)
log.InfoContext(ctx, "Successfully created Opsgenie alert")
// Save opsgenie alert info in plugin data.
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
@@ -479,10 +489,10 @@ func (a *App) postReviewNotes(ctx context.Context, reqID string, reqReviews []ty
return trace.Wrap(err)
}
if !ok {
logger.Get(ctx).Debug("Failed to post the note: plugin data is missing")
logger.Get(ctx).DebugContext(ctx, "Failed to post the note: plugin data is missing")
return nil
}
ctx, _ = logger.WithField(ctx, "opsgenie_alert_id", data.AlertID)
ctx, _ = logger.With(ctx, "opsgenie_alert_id", data.AlertID)
slice := reqReviews[oldCount:]
if len(slice) == 0 {
@@ -504,7 +514,7 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
serviceNames, err := a.getOnCallServiceNames(req)
if err != nil {
logger.Get(ctx).Debugf("Skipping the approval: %s", err)
logger.Get(ctx).DebugContext(ctx, "Skipping approval", "error", err)
return nil
}
@@ -537,14 +547,14 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
},
}); err != nil {
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
log.Debug("Already reviewed the request")
log.DebugContext(ctx, "Already reviewed the request")
return nil
}
return trace.Wrap(err, "submitting access request")
}
}
log.Info("Successfully submitted a request approval")
log.InfoContext(ctx, "Successfully submitted a request approval")
return nil
}
@@ -576,15 +586,15 @@ func (a *App) resolveAlert(ctx context.Context, reqID string, resolution Resolut
return trace.Wrap(err)
}
if !ok {
logger.Get(ctx).Debug("Failed to resolve the alert: plugin data is missing")
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the alert: plugin data is missing")
return nil
}
ctx, log := logger.WithField(ctx, "opsgenie_alert_id", alertID)
ctx, log := logger.With(ctx, "opsgenie_alert_id", alertID)
if err := a.opsgenie.ResolveAlert(ctx, alertID, resolution); err != nil {
return trace.Wrap(err)
}
log.Info("Successfully resolved the alert")
log.InfoContext(ctx, "Successfully resolved the alert")
return nil
}
+6 -4
View File
@@ -185,10 +185,10 @@ func (og Client) tryGetAlertRequestResult(ctx context.Context, reqID string) (Ge
for {
alertRequestResult, err := og.getAlertRequestResult(ctx, reqID)
if err == nil {
logger.Get(ctx).Debugf("Got alert request result: %+v", alertRequestResult)
logger.Get(ctx).DebugContext(ctx, "Got alert request result", "alert_id", alertRequestResult.Data.AlertID)
return alertRequestResult, nil
}
logger.Get(ctx).Debug("Failed to get alert request result:", err)
logger.Get(ctx).DebugContext(ctx, "Failed to get alert request result", "error", err)
if err := backoff.Do(ctx); err != nil {
return GetAlertRequestResult{}, trace.Wrap(err)
}
@@ -344,8 +344,10 @@ func (og Client) CheckHealth(ctx context.Context) error {
code = types.PluginStatusCode_OTHER_ERROR
}
if err := og.StatusSink.Emit(ctx, &types.PluginStatusV1{Code: code}); err != nil {
logger.Get(resp.Request.Context()).WithError(err).
WithField("code", resp.StatusCode()).Errorf("Error while emitting servicenow plugin status: %v", err)
logger.Get(resp.Request.Context()).ErrorContext(ctx, "Error while emitting servicenow plugin status",
"error", err,
"code", resp.StatusCode(),
)
}
}
@@ -32,7 +32,6 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/access/opsgenie"
@@ -314,7 +313,7 @@ func (s *FakeOpsgenie) GetSchedule(scheduleName string) ([]opsgenie.Responder, b
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+48 -35
View File
@@ -22,6 +22,7 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
"time"
@@ -38,6 +39,7 @@ import (
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -106,7 +108,6 @@ func (a *App) run(ctx context.Context) error {
var err error
log := logger.Get(ctx)
log.Infof("Starting Teleport Access PagerDuty Plugin")
if err = a.init(ctx); err != nil {
return trace.Wrap(err)
@@ -146,9 +147,9 @@ func (a *App) run(ctx context.Context) error {
a.mainJob.SetReady(ok)
if ok {
log.Info("Plugin is ready")
log.InfoContext(ctx, "Plugin is ready")
} else {
log.Error("Plugin is not ready")
log.ErrorContext(ctx, "Plugin is not ready")
}
<-watcherJob.Done()
@@ -202,25 +203,25 @@ func (a *App) init(ctx context.Context) error {
return trace.Wrap(err)
}
log.Debug("Starting PagerDuty API health check...")
log.DebugContext(ctx, "Starting PagerDuty API health check")
if err = a.pagerduty.HealthCheck(ctx); err != nil {
return trace.Wrap(err, "api health check failed. check your credentials and service_id settings")
}
log.Debug("PagerDuty API health check finished ok")
log.DebugContext(ctx, "PagerDuty API health check finished ok")
return nil
}
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
log := logger.Get(ctx)
log.Debug("Checking Teleport server version")
log.DebugContext(ctx, "Checking Teleport server version")
pong, err := a.teleport.Ping(ctx)
if err != nil {
if trace.IsNotImplemented(err) {
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
}
log.Error("Unable to get Teleport server version")
log.ErrorContext(ctx, "Unable to get Teleport server version")
return pong, trace.Wrap(err)
}
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
@@ -245,16 +246,16 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
}
op := event.Type
reqID := event.Resource.GetName()
ctx, _ = logger.WithField(ctx, "request_id", reqID)
ctx, _ = logger.With(ctx, "request_id", reqID)
switch op {
case types.OpPut:
ctx, _ = logger.WithField(ctx, "request_op", "put")
ctx, _ = logger.With(ctx, "request_op", "put")
req, ok := event.Resource.(types.AccessRequest)
if !ok {
return trace.Errorf("unexpected resource type %T", event.Resource)
}
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
var err error
switch {
@@ -263,21 +264,29 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
case req.GetState().IsResolved():
err = a.onResolvedRequest(ctx, req)
default:
log.WithField("event", event).Warn("Unknown request state")
log.WarnContext(ctx, "Unknown request state",
slog.Group("event",
slog.Any("type", logutils.StringerAttr(event.Type)),
slog.Group("resource",
"kind", event.Resource.GetKind(),
"name", event.Resource.GetName(),
),
),
)
return nil
}
if err != nil {
log.WithError(err).Error("Failed to process request")
log.ErrorContext(ctx, "Failed to process request", "error", err)
return trace.Wrap(err)
}
return nil
case types.OpDelete:
ctx, log := logger.WithField(ctx, "request_op", "delete")
ctx, log := logger.With(ctx, "request_op", "delete")
if err := a.onDeletedRequest(ctx, reqID); err != nil {
log.WithError(err).Error("Failed to process deleted request")
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
return trace.Wrap(err)
}
return nil
@@ -288,7 +297,7 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) error {
if len(req.GetSystemAnnotations()) == 0 {
logger.Get(ctx).Debug("Cannot proceed further. Request is missing any annotations")
logger.Get(ctx).DebugContext(ctx, "Cannot proceed further - request is missing any annotations")
return nil
}
@@ -370,11 +379,11 @@ func (a *App) tryNotifyService(ctx context.Context, req types.AccessRequest) (bo
serviceName, err := a.getNotifyServiceName(ctx, req)
if err != nil {
log.Debugf("Skipping the notification: %s", err)
log.DebugContext(ctx, "Skipping the notification", "error", err)
return false, trace.Wrap(errSkip)
}
ctx, _ = logger.WithField(ctx, "pd_service_name", serviceName)
ctx, _ = logger.With(ctx, "pd_service_name", serviceName)
service, err := a.pagerduty.FindServiceByName(ctx, serviceName)
if err != nil {
return false, trace.Wrap(err, "finding pagerduty service %s", serviceName)
@@ -420,8 +429,8 @@ func (a *App) createIncident(ctx context.Context, serviceID, reqID string, reqDa
if err != nil {
return trace.Wrap(err)
}
ctx, log := logger.WithField(ctx, "pd_incident_id", data.IncidentID)
log.Info("Successfully created PagerDuty incident")
ctx, log := logger.With(ctx, "pd_incident_id", data.IncidentID)
log.InfoContext(ctx, "Successfully created PagerDuty incident")
// Save pagerduty incident info in plugin data.
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
@@ -465,10 +474,10 @@ func (a *App) postReviewNotes(ctx context.Context, reqID string, reqReviews []ty
return trace.Wrap(err)
}
if !ok {
logger.Get(ctx).Debug("Failed to post the note: plugin data is missing")
logger.Get(ctx).DebugContext(ctx, "Failed to post the note: plugin data is missing")
return nil
}
ctx, _ = logger.WithField(ctx, "pd_incident_id", data.IncidentID)
ctx, _ = logger.With(ctx, "pd_incident_id", data.IncidentID)
slice := reqReviews[oldCount:]
if len(slice) == 0 {
@@ -490,36 +499,40 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
serviceNames, err := a.getOnCallServiceNames(req)
if err != nil {
logger.Get(ctx).Debugf("Skipping the approval: %s", err)
logger.Get(ctx).DebugContext(ctx, "Skipping approval", "error", err)
return nil
}
userName := req.GetUser()
if !lib.IsEmail(userName) {
logger.Get(ctx).Warningf("Skipping the approval: %q does not look like a valid email", userName)
logger.Get(ctx).WarnContext(ctx, "Skipping approval, found invalid email", "pd_user_email", userName)
return nil
}
user, err := a.pagerduty.FindUserByEmail(ctx, userName)
if err != nil {
if trace.IsNotFound(err) {
log.WithError(err).WithField("pd_user_email", userName).Debug("Skipping the approval: email is not found")
log.DebugContext(ctx, "Skipping approval, email is not found",
"error", err,
"pd_user_email", userName)
return nil
}
return trace.Wrap(err)
}
ctx, log = logger.WithFields(ctx, logger.Fields{
"pd_user_email": user.Email,
"pd_user_name": user.Name,
})
ctx, log = logger.With(ctx,
"pd_user_email", user.Email,
"pd_user_name", user.Name,
)
services, err := a.pagerduty.FindServicesByNames(ctx, serviceNames)
if err != nil {
return trace.Wrap(err)
}
if len(services) == 0 {
log.WithField("pd_service_names", serviceNames).Warning("Failed to find any service")
log.WarnContext(ctx, "Failed to find any service",
"pd_service_names", serviceNames,
)
return nil
}
@@ -536,7 +549,7 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
return trace.Wrap(err)
}
if len(escalationPolicyIDs) == 0 {
log.Debug("Skipping the approval: user is not on call")
log.DebugContext(ctx, "Skipping the approval: user is not on call")
return nil
}
@@ -561,13 +574,13 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
},
}); err != nil {
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
log.Debug("Already reviewed the request")
log.DebugContext(ctx, "Already reviewed the request")
return nil
}
return trace.Wrap(err, "submitting access request")
}
log.Info("Successfully submitted a request approval")
log.InfoContext(ctx, "Successfully submitted a request approval")
return nil
}
@@ -599,15 +612,15 @@ func (a *App) resolveIncident(ctx context.Context, reqID string, resolution Reso
return trace.Wrap(err)
}
if !ok {
logger.Get(ctx).Debug("Failed to resolve the incident: plugin data is missing")
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the incident: plugin data is missing")
return nil
}
ctx, log := logger.WithField(ctx, "pd_incident_id", incidentID)
ctx, log := logger.With(ctx, "pd_incident_id", incidentID)
if err := a.pagerduty.ResolveIncident(ctx, incidentID, resolution); err != nil {
return trace.Wrap(err)
}
log.Info("Successfully resolved the incident")
log.InfoContext(ctx, "Successfully resolved the incident")
return nil
}
+6 -6
View File
@@ -122,7 +122,7 @@ func onAfterPagerDutyResponse(sink common.StatusSink) resty.ResponseMiddleware {
defer cancel()
if err := sink.Emit(ctx, status); err != nil {
log.WithError(err).Errorf("Error while emitting PagerDuty plugin status: %v", err)
log.ErrorContext(ctx, "Error while emitting PagerDuty plugin status", "error", err)
}
if resp.IsError() {
@@ -288,7 +288,7 @@ func (p *Pagerduty) FindUserByEmail(ctx context.Context, userEmail string) (User
}
if len(result.Users) > 0 && result.More {
logger.Get(ctx).Warningf("PagerDuty returned too many results when querying by email %q", userEmail)
logger.Get(ctx).WarnContext(ctx, "PagerDuty returned too many results when querying user email", "email", userEmail)
}
return User{}, trace.NotFound("failed to find pagerduty user by email %s", userEmail)
@@ -387,10 +387,10 @@ func (p *Pagerduty) FilterOnCallPolicies(ctx context.Context, userID string, esc
if len(filteredIDSet) == 0 {
if anyData {
logger.Get(ctx).WithFields(logger.Fields{
"pd_user_id": userID,
"pd_escalation_policy_ids": escalationPolicyIDs,
}).Warningf("PagerDuty returned some oncalls array but none of them matched the query")
logger.Get(ctx).WarnContext(ctx, "PagerDuty returned some oncalls array but none of them matched the query",
"pd_user_id", userID,
"pd_escalation_policy_ids", escalationPolicyIDs,
)
}
return nil, nil
@@ -20,6 +20,7 @@ import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"github.com/alecthomas/kingpin/v2"
@@ -65,12 +66,13 @@ func main() {
if err := run(*path, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
}
func run(configPath string, debug bool) error {
ctx := context.Background()
conf, err := pagerduty.LoadConfig(configPath)
if err != nil {
return trace.Wrap(err)
@@ -84,7 +86,7 @@ func run(configPath string, debug bool) error {
return err
}
if debug {
logger.Standard().Debugf("DEBUG logging enabled")
slog.DebugContext(ctx, "DEBUG logging enabled")
}
app, err := pagerduty.NewApp(*conf)
@@ -94,8 +96,9 @@ func run(configPath string, debug bool) error {
go lib.ServeSignals(app, common.PluginShutdownTimeout)
logger.Standard().Infof("Starting Teleport Access PagerDuty Plugin %s:%s", teleport.Version, teleport.Gitref)
return trace.Wrap(
app.Run(context.Background()),
slog.InfoContext(ctx, "Starting Teleport Access PagerDuty Plugin",
"version", teleport.Version,
"git_ref", teleport.Gitref,
)
return trace.Wrap(app.Run(ctx))
}
@@ -32,7 +32,6 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/pagerduty"
"github.com/gravitational/teleport/integrations/lib/stringset"
@@ -565,6 +564,6 @@ func (s *FakePagerduty) CheckNewIncidentNote(ctx context.Context) (FakeIncidentN
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+47 -31
View File
@@ -21,6 +21,7 @@ package servicenow
import (
"context"
"fmt"
"log/slog"
"net/url"
"slices"
"strings"
@@ -41,6 +42,7 @@ import (
"github.com/gravitational/teleport/integrations/lib/logger"
"github.com/gravitational/teleport/integrations/lib/watcherjob"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -116,7 +118,7 @@ func (a *App) WaitReady(ctx context.Context) (bool, error) {
func (a *App) run(ctx context.Context) error {
log := logger.Get(ctx)
log.Infof("Starting Teleport Access Servicenow Plugin")
log.InfoContext(ctx, "Starting Teleport Access Servicenow Plugin")
if err := a.init(ctx); err != nil {
return trace.Wrap(err)
@@ -153,9 +155,9 @@ func (a *App) run(ctx context.Context) error {
}
a.mainJob.SetReady(ok)
if ok {
log.Info("ServiceNow plugin is ready")
log.InfoContext(ctx, "ServiceNow plugin is ready")
} else {
log.Error("ServiceNow plugin is not ready")
log.ErrorContext(ctx, "ServiceNow plugin is not ready")
}
<-watcherJob.Done()
@@ -190,25 +192,25 @@ func (a *App) init(ctx context.Context) error {
return trace.Wrap(err)
}
log.Debug("Starting API health check...")
log.DebugContext(ctx, "Starting API health check")
if err = a.serviceNow.CheckHealth(ctx); err != nil {
return trace.Wrap(err, "API health check failed")
}
log.Debug("API health check finished ok")
log.DebugContext(ctx, "API health check finished ok")
return nil
}
func (a *App) checkTeleportVersion(ctx context.Context) (proto.PingResponse, error) {
log := logger.Get(ctx)
log.Debug("Checking Teleport server version")
log.DebugContext(ctx, "Checking Teleport server version")
pong, err := a.teleport.Ping(ctx)
if err != nil {
if trace.IsNotImplemented(err) {
return pong, trace.Wrap(err, "server version must be at least %s", minServerVersion)
}
log.Error("Unable to get Teleport server version")
log.ErrorContext(ctx, "Unable to get Teleport server version")
return pong, trace.Wrap(err)
}
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
@@ -233,16 +235,16 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
}
op := event.Type
reqID := event.Resource.GetName()
ctx, _ = logger.WithField(ctx, "request_id", reqID)
ctx, _ = logger.With(ctx, "request_id", reqID)
switch op {
case types.OpPut:
ctx, _ = logger.WithField(ctx, "request_op", "put")
ctx, _ = logger.With(ctx, "request_op", "put")
req, ok := event.Resource.(types.AccessRequest)
if !ok {
return trace.Errorf("unexpected resource type %T", event.Resource)
}
ctx, log := logger.WithField(ctx, "request_state", req.GetState().String())
ctx, log := logger.With(ctx, "request_state", req.GetState().String())
var err error
switch {
@@ -251,21 +253,29 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
case req.GetState().IsResolved():
err = a.onResolvedRequest(ctx, req)
default:
log.WithField("event", event).Warnf("Unknown request state: %q", req.GetState())
log.WarnContext(ctx, "Unknown request state",
slog.Group("event",
slog.Any("type", logutils.StringerAttr(event.Type)),
slog.Group("resource",
"kind", event.Resource.GetKind(),
"name", event.Resource.GetName(),
),
),
)
return nil
}
if err != nil {
log.WithError(err).Error("Failed to process request")
log.ErrorContext(ctx, "Failed to process request", "error", err)
return trace.Wrap(err)
}
return nil
case types.OpDelete:
ctx, log := logger.WithField(ctx, "request_op", "delete")
ctx, log := logger.With(ctx, "request_op", "delete")
if err := a.onDeletedRequest(ctx, reqID); err != nil {
log.WithError(err).Error("Failed to process deleted request")
log.ErrorContext(ctx, "Failed to process deleted request", "error", err)
return trace.Wrap(err)
}
return nil
@@ -276,7 +286,7 @@ func (a *App) handleAccessRequest(ctx context.Context, event types.Event) error
func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) error {
reqID := req.GetName()
log := logger.Get(ctx).WithField("reqId", reqID)
log := logger.Get(ctx).With("req_id", reqID)
resourceNames, err := a.getResourceNames(ctx, req)
if err != nil {
@@ -303,7 +313,7 @@ func (a *App) onPendingRequest(ctx context.Context, req types.AccessRequest) err
}
if isNew {
log.Infof("Creating servicenow incident")
log.InfoContext(ctx, "Creating servicenow incident")
recipientAssignee := a.accessMonitoringRules.RecipientsFromAccessMonitoringRules(ctx, req)
assignees := []string{}
recipientAssignee.ForEach(func(r common.Recipient) {
@@ -375,8 +385,8 @@ func (a *App) createIncident(ctx context.Context, reqID string, reqData RequestD
if err != nil {
return trace.Wrap(err)
}
ctx, log := logger.WithField(ctx, "servicenow_incident_id", data.IncidentID)
log.Info("Successfully created Servicenow incident")
ctx, log := logger.With(ctx, "servicenow_incident_id", data.IncidentID)
log.InfoContext(ctx, "Successfully created Servicenow incident")
// Save servicenow incident info in plugin data.
_, err = a.modifyPluginData(ctx, reqID, func(existing *PluginData) (PluginData, bool) {
@@ -420,10 +430,10 @@ func (a *App) postReviewNotes(ctx context.Context, reqID string, reqReviews []ty
return trace.Wrap(err)
}
if !ok {
logger.Get(ctx).Debug("Failed to post the note: plugin data is missing")
logger.Get(ctx).DebugContext(ctx, "Failed to post the note: plugin data is missing")
return nil
}
ctx, _ = logger.WithField(ctx, "servicenow_incident_id", data.IncidentID)
ctx, _ = logger.With(ctx, "servicenow_incident_id", data.IncidentID)
slice := reqReviews[oldCount:]
if len(slice) == 0 {
@@ -445,22 +455,28 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
serviceNames, err := a.getOnCallServiceNames(req)
if err != nil {
logger.Get(ctx).Debugf("Skipping the approval: %s", err)
logger.Get(ctx).DebugContext(ctx, "Skipping the approval", "error", err)
return nil
}
log.Debugf("Checking the following shifts to see if the requester is on-call: %s", serviceNames)
log.DebugContext(ctx, "Checking the shifts to see if the requester is on-call", "shifts", serviceNames)
onCallUsers, err := a.getOnCallUsers(ctx, serviceNames)
if err != nil {
return trace.Wrap(err)
}
log.Debugf("Users on-call are: %s", onCallUsers)
log.DebugContext(ctx, "Users on-call are", "on_call_users", onCallUsers)
if userIsOnCall := slices.Contains(onCallUsers, req.GetUser()); !userIsOnCall {
log.Debugf("User %q is not on-call, not approving the request %q.", req.GetUser(), req.GetName())
log.DebugContext(ctx, "User is not on-call, not approving the request",
"user", req.GetUser(),
"request", req.GetName(),
)
return nil
}
log.Debugf("User %q is on-call. Auto-approving the request %q.", req.GetUser(), req.GetName())
log.DebugContext(ctx, "User is on-call, auto-approving the request",
"user", req.GetUser(),
"request", req.GetName(),
)
if _, err := a.teleport.SubmitAccessReview(ctx, types.AccessReviewSubmission{
RequestID: req.GetName(),
Review: types.AccessReview{
@@ -474,12 +490,12 @@ func (a *App) tryApproveRequest(ctx context.Context, req types.AccessRequest) er
},
}); err != nil {
if strings.HasSuffix(err.Error(), "has already reviewed this request") {
log.Debug("Already reviewed the request")
log.DebugContext(ctx, "Already reviewed the request")
return nil
}
return trace.Wrap(err, "submitting access request")
}
log.Info("Successfully submitted a request approval")
log.InfoContext(ctx, "Successfully submitted a request approval")
return nil
}
@@ -490,7 +506,7 @@ func (a *App) getOnCallUsers(ctx context.Context, serviceNames []string) ([]stri
respondersResult, err := a.serviceNow.GetOnCall(ctx, scheduleName)
if err != nil {
if trace.IsNotFound(err) {
log.WithError(err).Error("Failed to retrieve responder from schedule")
log.ErrorContext(ctx, "Failed to retrieve responder from schedule", "error", err)
continue
}
return nil, trace.Wrap(err)
@@ -528,15 +544,15 @@ func (a *App) resolveIncident(ctx context.Context, reqID string, resolution Reso
return trace.Wrap(err)
}
if !ok {
logger.Get(ctx).Debug("Failed to resolve the incident: plugin data is missing")
logger.Get(ctx).DebugContext(ctx, "Failed to resolve the incident: plugin data is missing")
return nil
}
ctx, log := logger.WithField(ctx, "servicenow_incident_id", incidentID)
ctx, log := logger.With(ctx, "servicenow_incident_id", incidentID)
if err := a.serviceNow.ResolveIncident(ctx, incidentID, resolution); err != nil {
return trace.Wrap(err)
}
log.Info("Successfully resolved the incident")
log.InfoContext(ctx, "Successfully resolved the incident")
return nil
}
+4 -1
View File
@@ -287,7 +287,10 @@ func (snc *Client) CheckHealth(ctx context.Context) error {
}
if err := snc.StatusSink.Emit(ctx, &types.PluginStatusV1{Code: code}); err != nil {
log := logger.Get(resp.Request.Context())
log.WithError(err).WithField("code", resp.StatusCode()).Errorf("Error while emitting servicenow plugin status: %v", err)
log.ErrorContext(ctx, "Error while emitting servicenow plugin status",
"error", err,
"code", resp.StatusCode(),
)
}
}
@@ -32,7 +32,6 @@ import (
"github.com/google/uuid"
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/servicenow"
"github.com/gravitational/teleport/integrations/lib/stringset"
@@ -284,6 +283,6 @@ func (s *FakeServiceNow) getOnCall(rotationName string) []string {
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
+3 -3
View File
@@ -29,7 +29,6 @@ import (
"github.com/go-resty/resty/v2"
"github.com/gravitational/trace"
"github.com/jonboulle/clockwork"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/accesslist"
@@ -37,6 +36,7 @@ import (
"github.com/gravitational/teleport/integrations/access/accessrequest"
"github.com/gravitational/teleport/integrations/access/common"
"github.com/gravitational/teleport/integrations/lib"
"github.com/gravitational/teleport/integrations/lib/logger"
pd "github.com/gravitational/teleport/integrations/lib/plugindata"
)
@@ -68,7 +68,7 @@ func onAfterResponseSlack(sink common.StatusSink) func(_ *resty.Client, resp *re
ctx, cancel := context.WithTimeout(context.Background(), statusEmitTimeout)
defer cancel()
if err := sink.Emit(ctx, status); err != nil {
log.Errorf("Error while emitting plugin status: %v", err)
logger.Get(ctx).ErrorContext(ctx, "Error while emitting plugin status", "error", err)
}
}()
@@ -139,7 +139,7 @@ func (b Bot) BroadcastAccessRequestMessage(ctx context.Context, recipients []com
// the case with most SSO setups.
userRecipient, err := b.FetchRecipient(ctx, reqData.User)
if err != nil {
log.Warningf("Unable to find user %s in Slack, will not be able to notify.", reqData.User)
logger.Get(ctx).WarnContext(ctx, "Unable to find user in Slack, will not be able to notify", "user", reqData.User)
}
// Include the user in the list of recipients if it exists.
@@ -20,6 +20,7 @@ import (
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"github.com/alecthomas/kingpin/v2"
@@ -65,12 +66,13 @@ func main() {
if err := run(*path, *debug); err != nil {
lib.Bail(err)
} else {
logger.Standard().Info("Successfully shut down")
slog.InfoContext(context.Background(), "Successfully shut down")
}
}
}
func run(configPath string, debug bool) error {
ctx := context.Background()
conf, err := slack.LoadSlackConfig(configPath)
if err != nil {
return trace.Wrap(err)
@@ -84,14 +86,15 @@ func run(configPath string, debug bool) error {
return trace.Wrap(err)
}
if debug {
logger.Standard().Debugf("DEBUG logging enabled")
slog.DebugContext(ctx, "DEBUG logging enabled")
}
app := slack.NewSlackApp(conf)
go lib.ServeSignals(app, common.PluginShutdownTimeout)
logger.Standard().Infof("Starting Teleport Access Slack Plugin %s:%s", teleport.Version, teleport.Gitref)
return trace.Wrap(
app.Run(context.Background()),
slog.InfoContext(ctx, "Starting Teleport Access Slack Plugin",
"version", teleport.Version,
"git_ref", teleport.Gitref,
)
return trace.Wrap(app.Run(ctx))
}
@@ -31,7 +31,6 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/integrations/access/slack"
)
@@ -315,6 +314,6 @@ func (s *FakeSlack) CheckMessageUpdateByResponding(ctx context.Context) (slack.M
func panicIf(err error) {
if err != nil {
log.Panicf("%v at %v", err, string(debug.Stack()))
panic(fmt.Sprintf("%v at %v", err, string(debug.Stack())))
}
}
@@ -31,8 +31,6 @@ import (
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
"github.com/gravitational/teleport/integrations/lib/logger"
)
type FakeFluentd struct {
@@ -150,7 +148,6 @@ func (f *FakeFluentd) GetURL() string {
func (f *FakeFluentd) Respond(w http.ResponseWriter, r *http.Request) {
req, err := io.ReadAll(r.Body)
if err != nil {
logger.Standard().WithError(err).Error("FakeFluentd Respond() failed to read body")
fmt.Fprintln(w, "NOK")
return
}
+5 -20
View File
@@ -46,8 +46,6 @@ const (
)
func main() {
// This initializes the legacy logrus logger. This has been kept in place
// in case any of the dependencies are still using logrus.
logger.Init()
ctx := kong.Parse(
@@ -64,17 +62,13 @@ func main() {
Format: "text",
}
if cli.Debug {
enableLogDebug()
logCfg.Severity = "debug"
}
log, err := logCfg.NewSLogLogger()
if err != nil {
fmt.Println(trace.DebugReport(trace.Wrap(err, "initializing logger")))
if err := logger.Setup(logCfg); err != nil {
fmt.Println(trace.DebugReport(err))
os.Exit(-1)
}
// Whilst this package mostly dependency injects slog, upstream dependencies
// may still use the default slog logger.
slog.SetDefault(log)
switch {
case ctx.Command() == "version":
@@ -86,25 +80,16 @@ func main() {
os.Exit(-1)
}
case ctx.Command() == "start":
err := start(log)
err := start(slog.Default())
if err != nil {
lib.Bail(err)
} else {
log.InfoContext(context.TODO(), "Successfully shut down")
slog.InfoContext(context.TODO(), "Successfully shut down")
}
}
}
// turn on log debugging
func enableLogDebug() {
err := logger.Setup(logger.Config{Severity: "debug", Output: "stderr"})
if err != nil {
fmt.Println(trace.DebugReport(err))
os.Exit(-1)
}
}
// start spawns the main process
func start(log *slog.Logger) error {
app, err := NewApp(&cli.Start, log)
+5 -3
View File
@@ -19,22 +19,24 @@
package lib
import (
"context"
"errors"
"log/slog"
"os"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
)
// Bail exits with nonzero exit code and prints an error to a log.
func Bail(err error) {
ctx := context.Background()
var agg trace.Aggregate
if errors.As(trace.Unwrap(err), &agg) {
for i, err := range agg.Errors() {
log.WithError(err).Errorf("Terminating with fatal error [%d]...", i+1)
slog.ErrorContext(ctx, "Terminating with fatal error", "error_number", i+1, "error", err)
}
} else {
log.WithError(err).Error("Terminating with fatal error...")
slog.ErrorContext(ctx, "Terminating with fatal error", "error", err)
}
os.Exit(1)
}
+5 -5
View File
@@ -22,12 +22,12 @@ import (
"context"
"errors"
"io"
"log/slog"
"os"
"strings"
"time"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
grpcbackoff "google.golang.org/grpc/backoff"
@@ -137,7 +137,7 @@ func NewIdentityFileWatcher(ctx context.Context, path string, interval time.Dura
}
if err := dynamicCred.Reload(); err != nil {
log.WithError(err).Error("Failed to reload identity file from disk.")
slog.ErrorContext(ctx, "Failed to reload identity file from disk", "error", err)
}
timer.Reset(interval)
}
@@ -152,7 +152,7 @@ func (cfg TeleportConfig) NewClient(ctx context.Context) (*client.Client, error)
case cfg.Addr != "":
addr = cfg.Addr
case cfg.AuthServer != "":
log.Warn("Configuration setting `auth_server` is deprecated, consider to change it to `addr`")
slog.WarnContext(ctx, "Configuration setting `auth_server` is deprecated, consider to change it to `addr`")
addr = cfg.AuthServer
}
@@ -173,13 +173,13 @@ func (cfg TeleportConfig) NewClient(ctx context.Context) (*client.Client, error)
}
if validCred, err := credentials.CheckIfExpired(creds); err != nil {
log.Warn(err)
slog.WarnContext(ctx, "found expired credentials", "error", err)
if !validCred {
return nil, trace.BadParameter(
"No valid credentials found, this likely means credentials are expired. In this case, please sign new credentials and increase their TTL if needed.",
)
}
log.Info("At least one non-expired credential has been found, continuing startup")
slog.InfoContext(ctx, "At least one non-expired credential has been found, continuing startup")
}
bk := grpcbackoff.DefaultConfig
+5 -6
View File
@@ -26,7 +26,6 @@ import (
"time"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/client/proto"
@@ -106,9 +105,9 @@ func (b *EmbeddedBot) start(ctx context.Context) {
go func() {
err := bot.Run(botCtx)
if err != nil {
log.Errorf("bot exited with error: %s", err)
slog.ErrorContext(botCtx, "bot exited with error", "error", err)
} else {
log.Infof("bot exited without error")
slog.InfoContext(botCtx, "bot exited without error")
}
b.errCh <- trace.Wrap(err)
}()
@@ -142,10 +141,10 @@ func (b *EmbeddedBot) waitForCredentials(ctx context.Context, deadline time.Dura
select {
case <-waitCtx.Done():
log.Warn("context canceled while waiting for the bot client")
slog.WarnContext(ctx, "context canceled while waiting for the bot client")
return nil, trace.Wrap(ctx.Err())
case <-b.credential.Ready():
log.Infof("credential ready")
slog.InfoContext(ctx, "credential ready")
}
return b.credential, nil
@@ -177,7 +176,7 @@ func (b *EmbeddedBot) StartAndWaitForCredentials(ctx context.Context, deadline t
// buildClient reads tbot's memory disttination, retrieves the certificates
// and builds a new Teleport client using those certs.
func (b *EmbeddedBot) buildClient(ctx context.Context) (*client.Client, error) {
log.Infof("Building a new client to connect to %s", b.cfg.AuthServer)
slog.InfoContext(ctx, "Building a new client to connect to cluster", "auth_server_address", b.cfg.AuthServer)
c, err := client.New(ctx, client.Config{
Addrs: []string{b.cfg.AuthServer},
Credentials: []client.Credentials{b.credential},
+8 -6
View File
@@ -24,6 +24,7 @@ import (
"crypto/x509"
"errors"
"fmt"
"log/slog"
"net"
"net/http"
"net/url"
@@ -33,7 +34,8 @@ import (
"github.com/gravitational/trace"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
// TLSConfig stores TLS configuration for a http service
@@ -178,7 +180,7 @@ func NewHTTP(config HTTPConfig) (*HTTP, error) {
if verify := config.TLS.VerifyClientCertificateFunc; verify != nil {
tlsConfig.VerifyPeerCertificate = func(_ [][]byte, chains [][]*x509.Certificate) error {
if err := verify(chains); err != nil {
log.WithError(err).Error("HTTPS client certificate verification failed")
slog.ErrorContext(context.Background(), "HTTPS client certificate verification failed", "error", err)
return err
}
return nil
@@ -217,7 +219,7 @@ func BuildURLPath(args ...interface{}) string {
// ListenAndServe runs a http(s) server on a provided port.
func (h *HTTP) ListenAndServe(ctx context.Context) error {
defer log.Debug("HTTP server terminated")
defer slog.DebugContext(ctx, "HTTP server terminated")
var err error
h.server.BaseContext = func(_ net.Listener) context.Context {
@@ -256,10 +258,10 @@ func (h *HTTP) ListenAndServe(ctx context.Context) error {
}
if h.Insecure {
log.Debugf("Starting insecure HTTP server on %s", addr)
slog.DebugContext(ctx, "Starting insecure HTTP server", "listen_addr", logutils.StringerAttr(addr))
err = h.server.Serve(listener)
} else {
log.Debugf("Starting secure HTTPS server on %s", addr)
slog.DebugContext(ctx, "Starting secure HTTPS server", "listen_addr", logutils.StringerAttr(addr))
err = h.server.ServeTLS(listener, h.CertFile, h.KeyFile)
}
if errors.Is(err, http.ErrServerClosed) {
@@ -288,7 +290,7 @@ func (h *HTTP) ServiceJob() ServiceJob {
return NewServiceJob(func(ctx context.Context) error {
MustGetProcess(ctx).OnTerminate(func(ctx context.Context) error {
if err := h.ShutdownWithTimeout(ctx, time.Second*5); err != nil {
log.Error("HTTP server graceful shutdown failed")
slog.ErrorContext(ctx, "HTTP server graceful shutdown failed")
return err
}
return nil
+27 -163
View File
@@ -20,16 +20,11 @@ package logger
import (
"context"
"io"
"io/fs"
"log/slog"
"os"
"strings"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
@@ -41,8 +36,6 @@ type Config struct {
Format string `toml:"format"`
}
type Fields = log.Fields
type contextKey struct{}
var extraFields = []string{logutils.LevelField, logutils.ComponentField, logutils.CallerField}
@@ -50,179 +43,50 @@ var extraFields = []string{logutils.LevelField, logutils.ComponentField, logutil
// Init sets up logger for a typical daemon scenario until configuration
// file is parsed
func Init() {
formatter := &logutils.TextFormatter{
EnableColors: utils.IsTerminal(os.Stderr),
ComponentPadding: 1, // We don't use components so strip the padding
ExtraFields: extraFields,
}
log.SetOutput(os.Stderr)
if err := formatter.CheckAndSetDefaults(); err != nil {
log.WithError(err).Error("unable to create text log formatter")
return
}
log.SetFormatter(formatter)
enableColors := utils.IsTerminal(os.Stderr)
logutils.Initialize(logutils.Config{
Severity: slog.LevelInfo.String(),
Format: "text",
ExtraFields: extraFields,
EnableColors: enableColors,
Padding: 1,
})
}
func Setup(conf Config) error {
var enableColors bool
switch conf.Output {
case "stderr", "error", "2":
log.SetOutput(os.Stderr)
enableColors = utils.IsTerminal(os.Stderr)
case "", "stdout", "out", "1":
log.SetOutput(os.Stdout)
enableColors = utils.IsTerminal(os.Stdout)
default:
// assume it's a file path:
logFile, err := os.Create(conf.Output)
if err != nil {
return trace.Wrap(err, "failed to create the log file")
}
log.SetOutput(logFile)
}
switch strings.ToLower(conf.Severity) {
case "info":
log.SetLevel(log.InfoLevel)
case "err", "error":
log.SetLevel(log.ErrorLevel)
case "debug":
log.SetLevel(log.DebugLevel)
case "warn", "warning":
log.SetLevel(log.WarnLevel)
case "trace":
log.SetLevel(log.TraceLevel)
default:
return trace.BadParameter("unsupported logger severity: '%v'", conf.Severity)
}
return nil
_, _, err := logutils.Initialize(logutils.Config{
Output: conf.Output,
Severity: conf.Severity,
Format: conf.Format,
ExtraFields: extraFields,
EnableColors: enableColors,
Padding: 1,
})
return trace.Wrap(err)
}
// NewSLogLogger builds a slog.Logger from the logger.Config.
// TODO(tross): Defer logging initialization to logutils.Initialize and use the
// global slog loggers once integrations has been updated to use slog.
func (conf Config) NewSLogLogger() (*slog.Logger, error) {
const (
// logFileDefaultMode is the preferred permissions mode for log file.
logFileDefaultMode fs.FileMode = 0o644
// logFileDefaultFlag is the preferred flags set to log file.
logFileDefaultFlag = os.O_WRONLY | os.O_CREATE | os.O_APPEND
)
var w io.Writer
switch conf.Output {
case "":
w = logutils.NewSharedWriter(os.Stderr)
case "stderr", "error", "2":
w = logutils.NewSharedWriter(os.Stderr)
case "stdout", "out", "1":
w = logutils.NewSharedWriter(os.Stdout)
case teleport.Syslog:
w = os.Stderr
sw, err := logutils.NewSyslogWriter()
if err != nil {
slog.Default().ErrorContext(context.Background(), "Failed to switch logging to syslog", "error", err)
break
}
// If syslog output has been configured and is supported by the operating system,
// then the shared writer is not needed because the syslog writer is already
// protected with a mutex.
w = sw
default:
// Assume this is a file path.
sharedWriter, err := logutils.NewFileSharedWriter(conf.Output, logFileDefaultFlag, logFileDefaultMode)
if err != nil {
return nil, trace.Wrap(err, "failed to init the log file shared writer")
}
w = logutils.NewWriterFinalizer[*logutils.FileSharedWriter](sharedWriter)
if err := sharedWriter.RunWatcherReopen(context.Background()); err != nil {
return nil, trace.Wrap(err)
}
}
level := new(slog.LevelVar)
switch strings.ToLower(conf.Severity) {
case "", "info":
level.Set(slog.LevelInfo)
case "err", "error":
level.Set(slog.LevelError)
case teleport.DebugLevel:
level.Set(slog.LevelDebug)
case "warn", "warning":
level.Set(slog.LevelWarn)
case "trace":
level.Set(logutils.TraceLevel)
default:
return nil, trace.BadParameter("unsupported logger severity: %q", conf.Severity)
}
configuredFields, err := logutils.ValidateFields(extraFields)
if err != nil {
return nil, trace.Wrap(err)
}
var slogLogger *slog.Logger
switch strings.ToLower(conf.Format) {
case "":
fallthrough // not set. defaults to 'text'
case "text":
enableColors := utils.IsTerminal(os.Stderr)
slogLogger = slog.New(logutils.NewSlogTextHandler(w, logutils.SlogTextHandlerConfig{
Level: level,
EnableColors: enableColors,
ConfiguredFields: configuredFields,
}))
slog.SetDefault(slogLogger)
case "json":
slogLogger = slog.New(logutils.NewSlogJSONHandler(w, logutils.SlogJSONHandlerConfig{
Level: level,
ConfiguredFields: configuredFields,
}))
slog.SetDefault(slogLogger)
default:
return nil, trace.BadParameter("unsupported log output format : %q", conf.Format)
}
return slogLogger, nil
}
func WithLogger(ctx context.Context, logger log.FieldLogger) context.Context {
return withLogger(ctx, logger)
}
func withLogger(ctx context.Context, logger log.FieldLogger) context.Context {
func WithLogger(ctx context.Context, logger *slog.Logger) context.Context {
return context.WithValue(ctx, contextKey{}, logger)
}
func WithField(ctx context.Context, key string, value interface{}) (context.Context, log.FieldLogger) {
logger := Get(ctx).WithField(key, value)
return withLogger(ctx, logger), logger
func With(ctx context.Context, args ...any) (context.Context, *slog.Logger) {
logger := Get(ctx).With(args...)
return WithLogger(ctx, logger), logger
}
func WithFields(ctx context.Context, logFields Fields) (context.Context, log.FieldLogger) {
logger := Get(ctx).WithFields(logFields)
return withLogger(ctx, logger), logger
}
func SetField(ctx context.Context, key string, value interface{}) context.Context {
ctx, _ = WithField(ctx, key, value)
return ctx
}
func SetFields(ctx context.Context, logFields Fields) context.Context {
ctx, _ = WithFields(ctx, logFields)
return ctx
}
func Get(ctx context.Context) log.FieldLogger {
if logger, ok := ctx.Value(contextKey{}).(log.FieldLogger); ok && logger != nil {
func Get(ctx context.Context) *slog.Logger {
if logger, ok := ctx.Value(contextKey{}).(*slog.Logger); ok && logger != nil {
return logger
}
return Standard()
}
func Standard() log.FieldLogger {
return log.StandardLogger()
return slog.Default()
}
+3 -4
View File
@@ -20,12 +20,11 @@ package lib
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
"time"
log "github.com/sirupsen/logrus"
)
type Terminable interface {
@@ -48,9 +47,9 @@ func ServeSignals(app Terminable, shutdownTimeout time.Duration) {
gracefulShutdown := func() {
tctx, tcancel := context.WithTimeout(ctx, shutdownTimeout)
defer tcancel()
log.Infof("Attempting graceful shutdown...")
slog.InfoContext(tctx, "Attempting graceful shutdown")
if err := app.Shutdown(tctx); err != nil {
log.Infof("Graceful shutdown failed. Trying fast shutdown...")
slog.InfoContext(tctx, "Graceful shutdown failed, attempting fast shutdown")
app.Close()
}
}
+16 -8
View File
@@ -27,6 +27,7 @@ import (
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/integrations/lib/logger"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
var regexpStatusCAPin = regexp.MustCompile(`CA pin +(sha256:[a-zA-Z0-9]+)`)
@@ -59,10 +60,14 @@ func (tctl Tctl) Sign(ctx context.Context, username, format, outPath string) err
outPath,
)
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
log.Debugf("Running %s", cmd)
log.DebugContext(ctx, "Running tctl auth sign", "command", logutils.StringerAttr(cmd))
output, err := cmd.CombinedOutput()
if err != nil {
log.WithError(err).WithField("args", args).Debug("tctl auth sign failed:", string(output))
log.DebugContext(ctx, "tctl auth sign failed",
"error", err,
"args", args,
"command_output", string(output),
)
return trace.Wrap(err, "tctl auth sign failed")
}
return nil
@@ -73,7 +78,7 @@ func (tctl Tctl) Create(ctx context.Context, resources []types.Resource) error {
log := logger.Get(ctx)
args := append(tctl.baseArgs(), "create")
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
log.Debugf("Running %s", cmd)
log.DebugContext(ctx, "Running tctl create", "command", logutils.StringerAttr(cmd))
stdinPipe, err := cmd.StdinPipe()
if err != nil {
return trace.Wrap(err, "failed to get stdin pipe")
@@ -81,16 +86,19 @@ func (tctl Tctl) Create(ctx context.Context, resources []types.Resource) error {
go func() {
defer func() {
if err := stdinPipe.Close(); err != nil {
log.WithError(trace.Wrap(err)).Error("Failed to close stdin pipe")
log.ErrorContext(ctx, "Failed to close stdin pipe", "error", err)
}
}()
if err := writeResourcesYAML(stdinPipe, resources); err != nil {
log.WithError(trace.Wrap(err)).Error("Failed to serialize resources stdin")
log.ErrorContext(ctx, "Failed to serialize resources stdin", "error", err)
}
}()
output, err := cmd.CombinedOutput()
if err != nil {
log.WithError(err).Debug("tctl create failed:", string(output))
log.DebugContext(ctx, "tctl create failed",
"error", err,
"command_output", string(output),
)
return trace.Wrap(err, "tctl create failed")
}
return nil
@@ -102,7 +110,7 @@ func (tctl Tctl) GetAll(ctx context.Context, query string) ([]types.Resource, er
args := append(tctl.baseArgs(), "get", query)
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
log.Debugf("Running %s", cmd)
log.DebugContext(ctx, "Running tctl get", "command", logutils.StringerAttr(cmd))
stdoutPipe, err := cmd.StdoutPipe()
if err != nil {
return nil, trace.Wrap(err, "failed to get stdout")
@@ -140,7 +148,7 @@ func (tctl Tctl) GetCAPin(ctx context.Context) (string, error) {
args := append(tctl.baseArgs(), "status")
cmd := exec.CommandContext(ctx, tctl.cmd(), args...)
log.Debugf("Running %s", cmd)
log.DebugContext(ctx, "Running tctl status", "command", logutils.StringerAttr(cmd))
output, err := cmd.Output()
if err != nil {
return "", trace.Wrap(err, "failed to get auth status")
@@ -93,7 +93,7 @@ func (s *Suite) initContexts(oldT *testing.T, newT *testing.T) {
} else {
baseCtx = context.Background()
}
baseCtx, _ = logger.WithField(baseCtx, "test", newT.Name())
baseCtx, _ = logger.With(baseCtx, "test", newT.Name())
baseCtx, cancel := context.WithCancel(baseCtx)
newT.Cleanup(cancel)
@@ -163,7 +163,7 @@ func (s *Suite) StartApp(app AppI) {
if err := app.Run(ctx); err != nil {
// We're in a goroutine so we can't just require.NoError(t, err).
// All we can do is to log an error.
logger.Get(ctx).WithError(err).Error("Application failed")
logger.Get(ctx).ErrorContext(ctx, "Application failed", "error", err)
}
}()
+8 -8
View File
@@ -130,23 +130,23 @@ func newJobWithEvents(events types.Events, config Config, fn EventFunc, watchIni
if config.FailFast {
return trace.WrapWithMessage(err, "Connection problem detected. Exiting as fail fast is on.")
}
log.WithError(err).Error("Connection problem detected. Attempting to reconnect.")
log.ErrorContext(ctx, "Connection problem detected, attempting to reconnect", "error", err)
case errors.Is(err, io.EOF):
if config.FailFast {
return trace.WrapWithMessage(err, "Watcher stream closed. Exiting as fail fast is on.")
}
log.WithError(err).Error("Watcher stream closed. Attempting to reconnect.")
log.ErrorContext(ctx, "Watcher stream closed attempting to reconnect", "error", err)
case lib.IsCanceled(err):
log.Debug("Watcher context is canceled")
log.DebugContext(ctx, "Watcher context is canceled")
return trace.Wrap(err)
default:
log.WithError(err).Error("Watcher event loop failed")
log.ErrorContext(ctx, "Watcher event loop failed", "error", err)
return trace.Wrap(err)
}
// To mitigate a potentially aggressive retry loop, we wait
if err := bk.Do(ctx); err != nil {
log.Debug("Watcher context was canceled while waiting before a reconnection")
log.DebugContext(ctx, "Watcher context was canceled while waiting before a reconnection")
return trace.Wrap(err)
}
}
@@ -162,7 +162,7 @@ func (job job) watchEvents(ctx context.Context) error {
}
defer func() {
if err := watcher.Close(); err != nil {
logger.Get(ctx).WithError(err).Error("Failed to close a watcher")
logger.Get(ctx).ErrorContext(ctx, "Failed to close a watcher", "error", err)
}
}()
@@ -170,7 +170,7 @@ func (job job) watchEvents(ctx context.Context) error {
return trace.Wrap(err)
}
logger.Get(ctx).Debug("Watcher connected")
logger.Get(ctx).DebugContext(ctx, "Watcher connected")
job.SetReady(true)
for {
@@ -253,7 +253,7 @@ func (job job) eventLoop(ctx context.Context) error {
event := *eventPtr
resource := event.Resource
if resource == nil {
log.Error("received an event with empty resource field")
log.ErrorContext(ctx, "received an event with empty resource field")
}
key := eventKey{kind: resource.GetKind(), name: resource.GetName()}
if queue, loaded := queues[key]; loaded {
@@ -21,38 +21,37 @@
package main
import (
"context"
"log/slog"
"os"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
func main() {
log.SetLevel(log.DebugLevel)
log.SetOutput(os.Stderr)
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
logutils.SlogTextHandlerConfig{
Level: slog.LevelDebug,
},
)))
ctx := context.Background()
inputPath := os.Getenv(crdgen.PluginInputPathEnvironment)
if inputPath == "" {
log.Error(
trace.BadParameter(
"When built with the 'debug' tag, the input path must be set through the environment variable: %s",
crdgen.PluginInputPathEnvironment,
),
)
slog.ErrorContext(ctx, "When built with the 'debug' tag, the input path must be set through the TELEPORT_PROTOC_READ_FILE environment variable")
os.Exit(-1)
}
log.Infof("This is a debug build, the protoc request is read from the file: '%s'", inputPath)
slog.InfoContext(ctx, "This is a debug build, the protoc request is read from the file", "input_path", inputPath)
req, err := crdgen.ReadRequestFromFile(inputPath)
if err != nil {
log.WithError(err).Error("error reading request from file")
slog.ErrorContext(ctx, "error reading request from file", "error", err)
os.Exit(-1)
}
if err := crdgen.HandleDocsRequest(req); err != nil {
log.WithError(err).Error("Failed to generate docs")
slog.ErrorContext(ctx, "Failed to generate docs", "error", err)
os.Exit(-1)
}
}
@@ -21,20 +21,26 @@
package main
import (
"context"
"log/slog"
"os"
"github.com/gogo/protobuf/vanity/command"
log "github.com/sirupsen/logrus"
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
func main() {
log.SetLevel(log.DebugLevel)
log.SetOutput(os.Stderr)
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
logutils.SlogTextHandlerConfig{
Level: slog.LevelDebug,
},
)))
req := command.Read()
if err := crdgen.HandleDocsRequest(req); err != nil {
log.WithError(err).Error("Failed to generate schema")
slog.ErrorContext(context.Background(), "Failed to generate schema", "error", err)
os.Exit(-1)
}
}
@@ -21,38 +21,37 @@
package main
import (
"context"
"log/slog"
"os"
"github.com/gravitational/trace"
log "github.com/sirupsen/logrus"
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
func main() {
log.SetLevel(log.DebugLevel)
log.SetOutput(os.Stderr)
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
logutils.SlogTextHandlerConfig{
Level: slog.LevelDebug,
},
)))
ctx := context.Background()
inputPath := os.Getenv(crdgen.PluginInputPathEnvironment)
if inputPath == "" {
log.Error(
trace.BadParameter(
"When built with the 'debug' tag, the input path must be set through the environment variable: %s",
crdgen.PluginInputPathEnvironment,
),
)
slog.ErrorContext(ctx, "When built with the 'debug' tag, the input path must be set through the TELEPORT_PROTOC_READ_FILE environment variable")
os.Exit(-1)
}
log.Infof("This is a debug build, the protoc request is read from the file: '%s'", inputPath)
slog.InfoContext(ctx, "This is a debug build, the protoc request is read from the file", "input_path", inputPath)
req, err := crdgen.ReadRequestFromFile(inputPath)
if err != nil {
log.WithError(err).Error("error reading request from file")
slog.ErrorContext(ctx, "error reading request from file", "error", err)
os.Exit(-1)
}
if err := crdgen.HandleCRDRequest(req); err != nil {
log.WithError(err).Error("Failed to generate schema")
slog.ErrorContext(ctx, "Failed to generate schema", "error", err)
os.Exit(-1)
}
}
@@ -21,20 +21,26 @@
package main
import (
"context"
"log/slog"
"os"
"github.com/gogo/protobuf/vanity/command"
log "github.com/sirupsen/logrus"
crdgen "github.com/gravitational/teleport/integrations/operator/crdgen"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
func main() {
log.SetLevel(log.DebugLevel)
log.SetOutput(os.Stderr)
slog.SetDefault(slog.New(logutils.NewSlogTextHandler(os.Stderr,
logutils.SlogTextHandlerConfig{
Level: slog.LevelDebug,
},
)))
req := command.Read()
if err := crdgen.HandleCRDRequest(req); err != nil {
log.WithError(err).Error("Failed to generate schema")
slog.ErrorContext(context.Background(), "Failed to generate schema", "error", err)
os.Exit(-1)
}
}
+1 -1
View File
@@ -21,7 +21,6 @@ require (
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1
github.com/jonboulle/clockwork v0.4.0
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.10.0
google.golang.org/grpc v1.69.2
google.golang.org/protobuf v1.36.2
@@ -307,6 +306,7 @@ require (
github.com/shirou/gopsutil/v4 v4.24.12 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sijms/go-ora/v2 v2.8.22 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
+4 -2
View File
@@ -17,9 +17,11 @@ limitations under the License.
package provider
import (
"context"
"log/slog"
"github.com/gravitational/trace"
"github.com/hashicorp/terraform-plugin-framework/diag"
log "github.com/sirupsen/logrus"
)
// diagFromWrappedErr wraps error with additional information
@@ -43,7 +45,7 @@ func diagFromWrappedErr(summary string, err error, kind string) diag.Diagnostic
// diagFromErr converts error to diag.Diagnostics. If logging level is debug, provides trace.DebugReport instead of short text.
func diagFromErr(summary string, err error) diag.Diagnostic {
if log.GetLevel() >= log.DebugLevel {
if slog.Default().Enabled(context.Background(), slog.LevelDebug) {
return diag.NewErrorDiagnostic(err.Error(), trace.DebugReport(err))
}
+28 -15
View File
@@ -19,6 +19,7 @@ package provider
import (
"context"
"fmt"
"log/slog"
"net"
"os"
"strconv"
@@ -29,13 +30,13 @@ import (
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
"github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/lib/utils"
logutils "github.com/gravitational/teleport/lib/utils/log"
)
const (
@@ -305,7 +306,7 @@ func (p *Provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq
return
}
log.WithFields(log.Fields{"addr": addr}).Debug("Using Teleport address")
slog.DebugContext(ctx, "Using Teleport address", "addr", addr)
dialTimeoutDuration, err := time.ParseDuration(dialTimeoutDurationStr)
if err != nil {
@@ -393,7 +394,7 @@ func (p *Provider) Configure(ctx context.Context, req tfsdk.ConfigureProviderReq
// checkTeleportVersion ensures that Teleport version is at least minServerVersion
func (p *Provider) checkTeleportVersion(ctx context.Context, client *client.Client, resp *tfsdk.ConfigureProviderResponse) bool {
log.Debug("Checking Teleport server version")
slog.DebugContext(ctx, "Checking Teleport server version")
pong, err := client.Ping(ctx)
if err != nil {
if trace.IsNotImplemented(err) {
@@ -403,13 +404,13 @@ func (p *Provider) checkTeleportVersion(ctx context.Context, client *client.Clie
)
return false
}
log.WithError(err).Debug("Teleport version check error!")
slog.DebugContext(ctx, "Teleport version check error", "error", err)
resp.Diagnostics.AddError("Unable to get Teleport server version!", "Unable to get Teleport server version!")
return false
}
err = utils.CheckMinVersion(pong.ServerVersion, minServerVersion)
if err != nil {
log.WithError(err).Debug("Teleport version check error!")
slog.DebugContext(ctx, "Teleport version check error", "error", err)
resp.Diagnostics.AddError("Teleport version check error!", err.Error())
return false
}
@@ -447,7 +448,7 @@ func (p *Provider) validateAddr(addr string, resp *tfsdk.ConfigureProviderRespon
_, _, err := net.SplitHostPort(addr)
if err != nil {
log.WithField("addr", addr).WithError(err).Debug("Teleport address format error!")
slog.DebugContext(context.Background(), "Teleport address format error", "error", err, "addr", addr)
resp.Diagnostics.AddError(
"Invalid Teleport address format",
fmt.Sprintf("Teleport address must be specified as host:port. Got %q", addr),
@@ -461,20 +462,32 @@ func (p *Provider) validateAddr(addr string, resp *tfsdk.ConfigureProviderRespon
// configureLog configures logging
func (p *Provider) configureLog() {
level := slog.LevelError
// Get Terraform log level
level, err := log.ParseLevel(os.Getenv("TF_LOG"))
if err != nil {
log.SetLevel(log.ErrorLevel)
} else {
log.SetLevel(level)
switch strings.ToLower(os.Getenv("TF_LOG")) {
case "panic", "fatal", "error":
level = slog.LevelError
case "warn", "warning":
level = slog.LevelWarn
case "info":
level = slog.LevelInfo
case "debug":
level = slog.LevelDebug
case "trace":
level = logutils.TraceLevel
}
log.SetFormatter(&log.TextFormatter{})
_, _, err := logutils.Initialize(logutils.Config{
Severity: level.String(),
Format: "text",
})
if err != nil {
return
}
// Show GRPC debug logs only if TF_LOG=DEBUG
if log.GetLevel() >= log.DebugLevel {
l := grpclog.NewLoggerV2(log.StandardLogger().Out, log.StandardLogger().Out, log.StandardLogger().Out)
grpclog.SetLoggerV2(l)
if level <= slog.LevelDebug {
grpclog.SetLoggerV2(grpclog.NewLoggerV2(os.Stderr, os.Stderr, os.Stderr))
}
}
+3
View File
@@ -42,6 +42,8 @@ type Config struct {
ExtraFields []string
// EnableColors dictates if output should be colored.
EnableColors bool
// Padding to use for various components.
Padding int
}
// Initialize configures the default global logger based on the
@@ -112,6 +114,7 @@ func Initialize(loggerConfig Config) (*slog.Logger, *slog.LevelVar, error) {
Level: level,
EnableColors: loggerConfig.EnableColors,
ConfiguredFields: configuredFields,
Padding: loggerConfig.Padding,
}))
slog.SetDefault(logger)
case "json":