porting all github actions from bluesky-social/indigo to tangled CI

SetIpfsWriter, GOLOG_* env to BSKYLOG_*

authored by Brian Olson and committed by Brian Olson 39f5b5f8 0a3197db

Changed files
+81 -16
util
+35
util/cliutil/ipfslog.go
··· 1 + package cliutil 2 + 3 + import ( 4 + "io" 5 + 6 + ipfslog "github.com/ipfs/go-log/v2" 7 + "go.uber.org/zap/zapcore" 8 + ) 9 + 10 + func SetIpfsWriter(out io.Writer, format string, level string) { 11 + var ze zapcore.Encoder 12 + switch format { 13 + case "json": 14 + ze = zapcore.NewJSONEncoder(zapcore.EncoderConfig{}) 15 + case "text": 16 + ze = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{}) 17 + default: 18 + ze = zapcore.NewConsoleEncoder(zapcore.EncoderConfig{}) 19 + } 20 + var zl zapcore.LevelEnabler 21 + switch level { 22 + case "debug": 23 + zl = zapcore.DebugLevel 24 + case "info": 25 + zl = zapcore.InfoLevel 26 + case "warn": 27 + zl = zapcore.WarnLevel 28 + case "error": 29 + zl = zapcore.ErrorLevel 30 + default: 31 + zl = zapcore.InfoLevel 32 + } 33 + nc := zapcore.NewCore(ze, zapcore.AddSync(out), zl) 34 + ipfslog.SetPrimaryCore(nc) 35 + }
+46 -16
util/cliutil/util.go
··· 260 260 // 261 261 // passing default cliutil.LogOptions{} is ok. 262 262 // 263 - // GOLOG_LOG_LEVEL=info|debug|warn|error 263 + // BSKYLOG_LOG_LEVEL=info|debug|warn|error 264 264 // 265 - // GOLOG_LOG_FMT=text|json 265 + // BSKYLOG_LOG_FMT=text|json 266 266 // 267 - // GOLOG_FILE=path (or "-" or "" for stdout), %T gets UnixMilli; if a path with '/', {prefix}/current becomes a link to active log file 267 + // BSKYLOG_FILE=path (or "-" or "" for stdout), %T gets UnixMilli; if a path with '/', {prefix}/current becomes a link to active log file 268 268 // 269 - // GOLOG_ROTATE_BYTES=int maximum size of log chunk before rotating 269 + // BSKYLOG_ROTATE_BYTES=int maximum size of log chunk before rotating 270 270 // 271 - // GOLOG_ROTATE_KEEP=int keep N olg logs (not including current) 271 + // BSKYLOG_ROTATE_KEEP=int keep N olg logs (not including current) 272 272 // 273 273 // (env vars derived from ipfs logging library) 274 274 func SetupSlog(options LogOptions) (*slog.Logger, error) { 275 + fmt.Fprintf(os.Stderr, "SetupSlog\n") 275 276 var hopts slog.HandlerOptions 276 277 hopts.Level = slog.LevelInfo 277 278 hopts.AddSource = true 278 279 if options.LogLevel == "" { 279 - options.LogLevel = os.Getenv("GOLOG_LOG_LEVEL") 280 + options.LogLevel = os.Getenv("BSKYLOG_LOG_LEVEL") 280 281 } 281 282 if options.LogLevel == "" { 282 283 hopts.Level = slog.LevelInfo ··· 297 298 } 298 299 } 299 300 if options.LogFormat == "" { 300 - options.LogFormat = os.Getenv("GOLOG_LOG_FMT") 301 + options.LogFormat = os.Getenv("BSKYLOG_LOG_FMT") 301 302 } 302 303 if options.LogFormat == "" { 303 304 options.LogFormat = "text" ··· 312 313 } 313 314 314 315 if options.LogPath == "" { 315 - options.LogPath = os.Getenv("GOLOG_FILE") 316 + options.LogPath = os.Getenv("BSKYLOG_FILE") 316 317 } 317 318 if options.LogRotateBytes == 0 { 318 - rotateBytesStr := os.Getenv("GOLOG_ROTATE_BYTES") 319 + rotateBytesStr := os.Getenv("BSKYLOG_ROTATE_BYTES") 319 320 if rotateBytesStr != "" { 320 321 rotateBytes, err := strconv.ParseInt(rotateBytesStr, 10, 64) 321 322 if err != nil { 322 - return nil, fmt.Errorf("invalid GOLOG_ROTATE_BYTES value: %w", err) 323 + return nil, fmt.Errorf("invalid BSKYLOG_ROTATE_BYTES value: %w", err) 323 324 } 324 325 options.LogRotateBytes = rotateBytes 325 326 } 326 327 } 327 328 if options.KeepOld == 0 { 328 329 keepOldUnset := true 329 - keepOldStr := os.Getenv("GOLOG_ROTATE_KEEP") 330 + keepOldStr := os.Getenv("BSKYLOG_ROTATE_KEEP") 330 331 if keepOldStr != "" { 331 332 keepOld, err := strconv.ParseInt(keepOldStr, 10, 64) 332 333 if err != nil { 333 - return nil, fmt.Errorf("invalid GOLOG_ROTATE_KEEP value: %w", err) 334 + return nil, fmt.Errorf("invalid BSKYLOG_ROTATE_KEEP value: %w", err) 334 335 } 335 336 keepOldUnset = false 336 337 options.KeepOld = int(keepOld) ··· 339 340 options.KeepOld = 2 340 341 } 341 342 } 343 + logaround := make(chan string, 100) 344 + go logbouncer(logaround) 342 345 var out io.Writer 343 346 if (options.LogPath == "") || (options.LogPath == "-") { 344 347 out = os.Stdout ··· 347 350 rotateBytes: options.LogRotateBytes, 348 351 outPathTemplate: options.LogPath, 349 352 keep: options.KeepOld, 353 + logaround: logaround, 350 354 } 351 355 } else { 352 356 var err error ··· 354 358 if err != nil { 355 359 return nil, fmt.Errorf("%s: %w", options.LogPath, err) 356 360 } 361 + fmt.Fprintf(os.Stderr, "SetupSlog create %#v\n", options.LogPath) 357 362 } 358 363 var handler slog.Handler 359 364 switch options.LogFormat { ··· 366 371 } 367 372 logger := slog.New(handler) 368 373 slog.SetDefault(logger) 374 + templateDirPart, _ := filepath.Split(options.LogPath) 375 + ents, _ := os.ReadDir(templateDirPart) 376 + for _, ent := range ents { 377 + fmt.Fprintf(os.Stdout, "%s\n", filepath.Join(templateDirPart, ent.Name())) 378 + } 379 + SetIpfsWriter(out, options.LogFormat, options.LogLevel) 369 380 return logger, nil 370 381 } 371 382 ··· 387 398 388 399 // keep the most recent N log files (not including current) 389 400 keep int 401 + 402 + // write strings to this from inside the log system, a task outside the log system hands them to slog.Info() 403 + logaround chan<- string 404 + } 405 + 406 + func logbouncer(out <-chan string) { 407 + var logger *slog.Logger 408 + for line := range out { 409 + fmt.Fprintf(os.Stderr, "ll %s\n", line) 410 + if logger == nil { 411 + // lazy to make sure it crops up after slog Default has been set 412 + logger = slog.Default().With("system", "logging") 413 + } 414 + logger.Info(line) 415 + } 390 416 } 391 417 392 418 var currentMatcher = regexp.MustCompile("current_\\d+") ··· 401 427 // find old logs 402 428 templateDirPart, templateNamePart := filepath.Split(w.outPathTemplate) 403 429 if dirpart != templateDirPart { 404 - fmt.Fprintf(os.Stderr, "current dir part %#v != template dir part %#v\n", w.currentPath, w.outPathTemplate) 430 + w.logaround <- fmt.Sprintf("current dir part %#v != template dir part %#v\n", w.currentPath, w.outPathTemplate) 405 431 return 406 432 } 407 433 // build a regexp that is string literal parts with \d+ replacing the UnixMilli part ··· 418 444 } 419 445 tmre, err := regexp.Compile(sb.String()) 420 446 if err != nil { 421 - fmt.Fprintf(os.Stderr, "failed to compile old log template regexp: %#v\n", err) 447 + w.logaround <- fmt.Sprintf("failed to compile old log template regexp: %#v\n", err) 422 448 return 423 449 } 424 450 dir, err := os.ReadDir(dirpart) 425 451 if err != nil { 426 - fmt.Fprintf(os.Stderr, "failed to read old log template dir: %#v\n", err) 452 + w.logaround <- fmt.Sprintf("failed to read old log template dir: %#v\n", err) 427 453 return 428 454 } 429 455 var found []fs.FileInfo ··· 450 476 fullpath := filepath.Join(dirpart, fi.Name()) 451 477 err = os.Remove(fullpath) 452 478 if err != nil { 453 - fmt.Fprintf(os.Stderr, "failed to rm old log: %#v\n", err) 479 + w.logaround <- fmt.Sprintf("failed to rm old log: %#v\n", err) 454 480 // but keep going 455 481 } 456 482 // maybe it would be safe to debug-log old log removal from within the logging infrastructure? ··· 489 515 earlyWeakErrors = append(earlyWeakErrors, err) 490 516 return errors.Join(earlyWeakErrors...), nil 491 517 } 518 + w.logaround <- fmt.Sprintf("new log file %#v", w.currentPath) 492 519 w.cleanOldLogs() 493 520 dirpart, _ := filepath.Split(w.currentPath) 494 521 if dirpart != "" { ··· 534 561 if err != nil { 535 562 earlyWeakErrors = append(earlyWeakErrors, err) 536 563 return wrote, errors.Join(earlyWeakErrors...) 564 + } 565 + if earlyWeakErrors != nil { 566 + w.logaround <- fmt.Sprintf("ok, but: %s", errors.Join(earlyWeakErrors...).Error()) 537 567 } 538 568 return wrote, nil 539 569 }