Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cgroup logging with slog #269

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

cgroup logging with slog #269

wants to merge 1 commit into from

Conversation

radia78
Copy link

@radia78 radia78 commented Feb 10, 2025

Note: On the log side, the default logger that’s named “std” and functions like Printf is utilizing the output method of std. On the slog side, the default logger is an object called “defaultLogger” which is just a slog logger whose handler is std.output. When we create a new slog logger with a JSONHandler and pass it through slog.SetDefault, “defaultLogger” now points to that new slog logger. In addition, it changes the “out” field of “std” and it now wraps our new JSONHandler.

When log.Printf is called, it first uses its own lock before "writing" the output. When "writing" the output, it uses the JSONHandler's "Write" method that uses its own lock before writing the actual output in JSON format. Since this is a nested lock with two different locks, it should 1) not jumble the output and 2) not cause a deadlock.

Modified cgroups to use slog with a JSON handler and have level-specific attributes for the logs. For example, at the pool level it should log "cg-pool: *pool_name", and at the cg-level it should log "cg-pool: *pool-name, cg: *cg-name".

Downside, every call to log.Printf will be a JSON format, so currently working on a way so that calls to log.Printf would just show regular log but cgroup logs will show-up as JSON format.

Copy link
Member

@tylerharter tylerharter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work! Looking forward to the next iteration.

}

// For cgroups, it should clone the default logger and append an additional attribute (i.e. name, id, etc.)
func LoadCgroupLogger(args ...any) *slog.Logger {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this wrapper around .With do anything interesting? Why not just directly call .With when needed?


// Default logger for the entire system (Any call from log will immediately be written with a JSON handler)
// TODO: Only format it as JSON for cgroups but any other systems calling log.Printf should just get a regular log output
var defaultSystemLogger = slog.New(slog.NewJSONHandler(os.Stdout, nil))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config should have an option about whether to use JSON our Text formatting of output.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like how #203 was handling the config. Can we do something similar?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to handle different logging levels for different subsystems. How will that work out? It seems like you could create different handlers (since you specify the level when you create the handler), but will we have multiple locks and jumbled output then?

"os"
)

// Default logger for the entire system (Any call from log will immediately be written with a JSON handler)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have some more details comments about logging and locking in the PR itself. I think we should do most of the explanation in the actual comments. Please include links/quotes to documentation where appropriate.

var defaultSystemLogger = slog.New(slog.NewJSONHandler(os.Stdout, nil))

// Set the defaultSystemLogger as default logger when common is initialized
func init() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably need to do this later, after the config is loaded.

@@ -33,11 +33,12 @@ func NewCgroupPool(name string) (*CgroupPool, error) {
recycled: make(chan *CgroupImpl, CGROUP_RESERVE),
quit: make(chan chan bool),
nextID: 0,
log: common.LoadCgroupLogger("cg-pool", path.Base(path.Dir(common.Conf.Worker_dir))+"-"+name),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll usually only have one cgroup pool, so I don't think it's worth including this path in every log line.

@@ -59,30 +60,24 @@ func (pool *CgroupPool) NewCgroup() Cgroup {
cg := &CgroupImpl{
name: fmt.Sprintf("cg-%d", pool.nextID),
pool: pool,
log: pool.log.With("cg", fmt.Sprintf("cg-%d", pool.nextID)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's avoid copying code for the cg name in case we choose a different naming scheme later. Better to store the name in a separate variable, then use it in both places.

@tylerharter
Copy link
Member

Thanks for taking this on! This is attempting to do the same as a prior PR that has been abandoned: #203. For that one, we were not sure we had a good strategy to avoid jumbled output, and there was not further progress. The locking gets tricky when both log and slog are used, and when multiple levels in slog are used (need to make sure loggers with different handlers wrapping the same std output actually coordinate).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants