|
63 | 63 | from pathlib import Path |
64 | 64 |
|
65 | 65 |
|
| 66 | +# Optional OpenTelemetry instrumentation. When transformers-ci[otel] is installed |
| 67 | +# and OTEL_* env is configured (e.g. by `configure-ci-otel` in CI), each checker |
| 68 | +# run emits a span; otherwise this is a complete no-op. The producer-side helper |
| 69 | +# lives in transformers-ci, so importing it must never be a hard dependency. |
| 70 | +try: |
| 71 | + from transformersci.otel import instrument as _otel |
| 72 | +except ImportError: # transformers-ci[otel] not installed → tracing disabled |
| 73 | + _otel = None |
| 74 | + |
| 75 | + |
| 76 | +class _NullTrace: |
| 77 | + """No-op with the same shape as transformersci.otel.instrument's Run/Step.""" |
| 78 | + |
| 79 | + def run(self, *args, **kwargs): |
| 80 | + return self |
| 81 | + |
| 82 | + def step(self, *args, **kwargs): |
| 83 | + return self |
| 84 | + |
| 85 | + def __enter__(self): |
| 86 | + return self |
| 87 | + |
| 88 | + def __exit__(self, *exc): |
| 89 | + return False |
| 90 | + |
| 91 | + def set_exit_code(self, returncode): |
| 92 | + pass |
| 93 | + |
| 94 | + |
| 95 | +_tracer = _otel if _otel is not None else _NullTrace() |
| 96 | + |
| 97 | + |
66 | 98 | UTILS_DIR = Path(__file__).parent |
67 | 99 | REPO_ROOT = UTILS_DIR.parent |
68 | 100 | CACHE_PATH = UTILS_DIR / ".checkers_cache.json" |
@@ -545,82 +577,94 @@ def main(): |
545 | 577 | failures = [] |
546 | 578 | skipped = 0 |
547 | 579 | total_start = time.perf_counter() |
548 | | - for name in names: |
549 | | - label = CHECKERS[name][0] |
550 | | - |
551 | | - # Skip if all relevant files are unchanged since last clean run |
552 | | - if cache is not None and cache.is_current(name): |
553 | | - skipped += 1 |
554 | | - if is_tty: |
555 | | - print(f"{GREEN}✓ {label} (cached){RESET}\n") |
556 | | - else: |
557 | | - print(f"{label} (cached)\n", flush=True) |
558 | | - continue |
559 | | - |
560 | | - cmd_str = get_checker_command(name, fix=args.fix) |
561 | | - checker_start = time.perf_counter() |
562 | | - |
563 | | - if is_tty: |
564 | | - window = SlidingWindow(label, max_lines=10) |
565 | | - if cmd_str: |
566 | | - window.add_line(f"$ {cmd_str}") |
567 | | - rc, output = run_checker(name, fix=args.fix, line_callback=window.add_line) |
568 | | - elapsed = time.perf_counter() - checker_start |
569 | | - window.finish(success=(rc == 0), elapsed=elapsed, show_lines=(rc == 0)) |
570 | | - if rc != 0: |
571 | | - print() |
572 | | - _print_output(output) |
573 | | - print() |
574 | | - if rc == 0 and cache is not None: |
575 | | - cache.update(name) |
576 | | - elif rc != 0: |
577 | | - if cache is not None: |
578 | | - cache.invalidate(name) |
579 | | - failures.append(name) |
580 | | - if not args.keep_going: |
581 | | - if cache is not None: |
582 | | - cache.save() |
583 | | - sys.exit(1) |
584 | | - else: |
585 | | - print(f"{label}", flush=True) |
586 | | - if cmd_str: |
587 | | - print(f"$ {cmd_str}", flush=True) |
588 | | - if is_ci: |
589 | | - streamed_output = [] |
590 | | - |
591 | | - def print_line(line): |
592 | | - streamed_output.append(line) |
593 | | - print(line, end="", flush=True) |
594 | | - |
595 | | - rc, output = run_checker(name, fix=args.fix, line_callback=print_line) |
596 | | - if rc != 0 and output: |
597 | | - streamed_text = "".join(streamed_output) |
598 | | - if output.startswith(streamed_text): |
599 | | - _print_output(output[len(streamed_text) :]) |
600 | | - elif output != streamed_text: |
| 580 | + # One trace per checkers run; one span per checker. No-op unless |
| 581 | + # transformers-ci[otel] is installed and OTEL_* is configured. The job name |
| 582 | + # rides in via OTEL_RESOURCE_ATTRIBUTES (set by configure-ci-otel), so the |
| 583 | + # value below is only a fallback for un-wrapped local runs. |
| 584 | + job = os.environ.get("TRANSFORMERS_TEST_OTEL_JOB", "local_checks") |
| 585 | + with _tracer.run(job, attributes={"transformers.check.mode": "fix" if args.fix else "check"}) as otel_run: |
| 586 | + for name in names: |
| 587 | + label = CHECKERS[name][0] |
| 588 | + with otel_run.step( |
| 589 | + f"utils/checkers.py::{name}", |
| 590 | + attributes={"transformers.check.name": name, "transformers.check.label": label}, |
| 591 | + ) as otel_step: |
| 592 | + # Skip if all relevant files are unchanged since last clean run |
| 593 | + if cache is not None and cache.is_current(name): |
| 594 | + skipped += 1 |
| 595 | + otel_step.set_exit_code(0) |
| 596 | + if is_tty: |
| 597 | + print(f"{GREEN}✓ {label} (cached){RESET}\n") |
| 598 | + else: |
| 599 | + print(f"{label} (cached)\n", flush=True) |
| 600 | + continue |
| 601 | + |
| 602 | + cmd_str = get_checker_command(name, fix=args.fix) |
| 603 | + checker_start = time.perf_counter() |
| 604 | + |
| 605 | + if is_tty: |
| 606 | + window = SlidingWindow(label, max_lines=10) |
| 607 | + if cmd_str: |
| 608 | + window.add_line(f"$ {cmd_str}") |
| 609 | + rc, output = run_checker(name, fix=args.fix, line_callback=window.add_line) |
| 610 | + elapsed = time.perf_counter() - checker_start |
| 611 | + window.finish(success=(rc == 0), elapsed=elapsed, show_lines=(rc == 0)) |
| 612 | + otel_step.set_exit_code(rc) |
| 613 | + if rc != 0: |
| 614 | + print() |
601 | 615 | _print_output(output) |
602 | | - else: |
603 | | - rc, output = run_checker(name, fix=args.fix) |
604 | | - if rc == 0: |
605 | | - tail = output.splitlines()[-10:] |
606 | | - if tail: |
607 | | - print("\n".join(tail), flush=True) |
| 616 | + print() |
| 617 | + if rc == 0 and cache is not None: |
| 618 | + cache.update(name) |
| 619 | + elif rc != 0: |
| 620 | + if cache is not None: |
| 621 | + cache.invalidate(name) |
| 622 | + failures.append(name) |
| 623 | + if not args.keep_going: |
| 624 | + if cache is not None: |
| 625 | + cache.save() |
| 626 | + sys.exit(1) |
608 | 627 | else: |
609 | | - _print_output(output) |
610 | | - elapsed = time.perf_counter() - checker_start |
611 | | - status = "OK" if rc == 0 else "FAILED" |
612 | | - print(f"{status} ({format_elapsed(elapsed)})", flush=True) |
613 | | - print(flush=True) |
614 | | - if rc == 0 and cache is not None: |
615 | | - cache.update(name) |
616 | | - elif rc != 0: |
617 | | - if cache is not None: |
618 | | - cache.invalidate(name) |
619 | | - failures.append(name) |
620 | | - if not args.keep_going: |
621 | | - if cache is not None: |
622 | | - cache.save() |
623 | | - sys.exit(1) |
| 628 | + print(f"{label}", flush=True) |
| 629 | + if cmd_str: |
| 630 | + print(f"$ {cmd_str}", flush=True) |
| 631 | + if is_ci: |
| 632 | + streamed_output = [] |
| 633 | + |
| 634 | + def print_line(line): |
| 635 | + streamed_output.append(line) |
| 636 | + print(line, end="", flush=True) |
| 637 | + |
| 638 | + rc, output = run_checker(name, fix=args.fix, line_callback=print_line) |
| 639 | + if rc != 0 and output: |
| 640 | + streamed_text = "".join(streamed_output) |
| 641 | + if output.startswith(streamed_text): |
| 642 | + _print_output(output[len(streamed_text) :]) |
| 643 | + elif output != streamed_text: |
| 644 | + _print_output(output) |
| 645 | + else: |
| 646 | + rc, output = run_checker(name, fix=args.fix) |
| 647 | + if rc == 0: |
| 648 | + tail = output.splitlines()[-10:] |
| 649 | + if tail: |
| 650 | + print("\n".join(tail), flush=True) |
| 651 | + else: |
| 652 | + _print_output(output) |
| 653 | + elapsed = time.perf_counter() - checker_start |
| 654 | + status = "OK" if rc == 0 else "FAILED" |
| 655 | + print(f"{status} ({format_elapsed(elapsed)})", flush=True) |
| 656 | + print(flush=True) |
| 657 | + otel_step.set_exit_code(rc) |
| 658 | + if rc == 0 and cache is not None: |
| 659 | + cache.update(name) |
| 660 | + elif rc != 0: |
| 661 | + if cache is not None: |
| 662 | + cache.invalidate(name) |
| 663 | + failures.append(name) |
| 664 | + if not args.keep_going: |
| 665 | + if cache is not None: |
| 666 | + cache.save() |
| 667 | + sys.exit(1) |
624 | 668 |
|
625 | 669 | if cache is not None: |
626 | 670 | cache.save() |
|
0 commit comments