Skip to content

Commit 622502d

Browse files
authored
Improve copilot-instructions.md for first-pass PR review (open-telemetry#18632)
1 parent 75e2241 commit 622502d

2 files changed

Lines changed: 172 additions & 23 deletions

File tree

.github/copilot-instructions.md

Lines changed: 159 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,173 @@
11
# OpenTelemetry Java Instrumentation
22

3-
## Scope
3+
First-pass PR review rules. A deep review with full knowledge files runs
4+
separately later in the PR lifecycle. **Prefer silence over uncertainty.** Only
5+
flag substantive issues on changed lines. Skip stylistic preferences not listed
6+
below. Do not nitpick.
47

5-
Repository-wide defaults for Copilot behavior.
6-
Keep scoped language or file-type rules in `.github/instructions/*.instructions.md`.
8+
Use category tags like `[Style]`, `[Naming]`, `[Testing]`, `[General]`.
79

8-
## Repository Layout
10+
## [Style] Style Guide
911

10-
- Workspace-level overview: `.github/README.md`
11-
- Scoped instructions and `applyTo` patterns: `.github/instructions/README.md`
12-
- Agent review and implementation knowledge index: `.github/agents/knowledge/README.md`
12+
Follow `docs/contributing/style-guide.md`.
1313

14-
## Core References
14+
- **Visibility**: principle of least access. Use the most restrictive modifier
15+
that still works. Static fields should be `private` unless they are
16+
constant-like with a `SCREAMING_SNAKE_CASE` name.
17+
- **`final` on classes**: declare public API classes `final` where possible. Do
18+
**not** add `final` in `javaagent/src/main/`, in `.internal` packages, or in
19+
test code (paths under `src/test/` or modules whose name starts/ends with
20+
`testing` or `tests`).
21+
- **`final` on parameters and local variables**: never declare them `final`.
22+
- **Null comparisons**: use `value == null` / `value != null`, not
23+
`null == value` / `null != value`. Applies to Java, Kotlin, and Scala.
24+
- **`equals` operand order**: prefer `value.equals(CONSTANT)` over
25+
`CONSTANT.equals(value)`. Do not flip operand order solely as a defensive
26+
null-safety cleanup; only flip when `value` can actually be null.
27+
- **Class organization**: static fields → static initializer → instance fields
28+
→ constructors → methods → nested classes. Place calling methods above the
29+
methods they call.
30+
- **Static factory entry points**: place them below fields and immediately
31+
above constructors — treat factories and constructors as one construction
32+
section.
33+
- **Static utility classes**: place the private no-arg constructor after all
34+
methods.
35+
- **Uppercase field names**: use `SCREAMING_SNAKE_CASE` only for constant-like
36+
values — literals, immutable value constants (e.g. `Duration` timeouts),
37+
semantic keys/handles (`AttributeKey`, `ContextKey`, `VirtualField`,
38+
`MethodHandle`, `Pattern`), and canonical singletons (`INSTANCE`, `EMPTY`,
39+
`NOOP`). Use lower camel case for runtime collaborators (loggers,
40+
instrumenters, helpers, caches), even when `static final`.
41+
- **Avoid throwaway forwarding locals** that mirror an existing constant,
42+
argument, or SDK field into both an SDK call and span attributes; pass the
43+
original value directly unless real derivation justifies a local.
44+
- **`Optional`**: do not use in public API signatures or on the hot path.
45+
- **Semconv constants**: in `library/src/main/`, copy incubating semconv
46+
constants locally as `private static final` with a `// copied from <Class>`
47+
comment; do not depend on the semconv incubating artifact. In
48+
`javaagent/src/main/` and tests, use semconv constants directly.
49+
- **`@Nullable` in tests**: do not add it to test code.
1550

16-
- Style guide and core conventions: `docs/contributing/style-guide.md`
17-
- Review and implementation knowledge by topic: `.github/agents/knowledge/README.md`
51+
## [Style] `@SuppressWarnings` Scoping
1852

19-
## Knowledge Loading
53+
Place `@SuppressWarnings` on the single member that needs it. Use class-level
54+
only when two or more members would need the same suppression.
2055

21-
For coding, fix, and refactoring tasks, consult `.github/agents/knowledge/README.md`
22-
before making substantial changes.
56+
## [Naming] Catch Variable Names
2357

24-
Use the knowledge index to load only the article(s) relevant to the current task.
25-
Do not load the entire knowledge folder by default.
58+
In **catch clauses only** (not method/lambda parameters or fields):
2659

27-
## Gradle Execution Rules
60+
- Used exception → `e` (or `error` for a specific `*Error` subtype).
61+
- Used exception in nested catch where outer already uses `e``f`.
62+
- Used `Throwable``t`.
63+
- Intentionally unused → `ignored` (or `ignore` if `ignored` would shadow an
64+
outer catch).
2865

29-
Never use `--rerun-tasks`. Use `--rerun` when needed.
66+
## [Naming] Public API Getters
3067

31-
Builds and tests in this repository can take several minutes.
32-
Run Gradle commands with timeout `0` (no timeout), and wait for completion.
33-
Do not treat slow output as a hang by default.
68+
Public API getters use `get*` (or `is*` for booleans).
3469

35-
Never pipe Gradle output through `tail`, `head`, `grep`, or any other command.
36-
Piping masks the Gradle exit code — the shell reports the exit code of the last
37-
pipe segment, not Gradle, so a failing build silently appears to succeed.
70+
## [Style] No Redundant Null Guards on Attribute Puts
71+
72+
`AttributesBuilder.put`, `Span.setAttribute`, `SpanBuilder.setAttribute`, and
73+
`LogRecordBuilder.setAttribute` are no-ops when the value is `null`. Do not wrap
74+
calls in `if (value != null)` when the value can be passed straight through:
75+
76+
```java
77+
// BAD
78+
String v = getSomething();
79+
if (v != null) {
80+
attributes.put(SOME_KEY, v);
81+
}
82+
// GOOD
83+
attributes.put(SOME_KEY, getSomething());
84+
```
85+
86+
Do **not** flag when the guard protects a dereference or derived computation
87+
(e.g. `view.getClass().getName()`). When in doubt, stay silent.
88+
89+
## [Testing] General Patterns
90+
91+
- Use AssertJ (`assertThat(...)`) for assertions in new test code. Do not
92+
use JUnit `Assert.*` or Hamcrest `assertThat`.
93+
- Do not add AssertJ `.as(...)` descriptions or `.withFailMessage(...)` in
94+
tests. Direct assertions whose failure output already shows the unexpected
95+
values are preferred.
96+
- Test methods do not need `throws Exception` clauses unless actually required.
97+
- Prefer the nearest common parent in `catch` (including `Exception` /
98+
`Throwable`) over multi-catch.
99+
- Use `e` / `f` / `t` / `ignored` per the naming rules above.
100+
101+
## [Testing] AssertJ Idiomatic Simplifications
102+
103+
Prefer built-in AssertJ collection/string/map assertions over manual extraction:
104+
105+
| Anti-pattern | Idiomatic |
106+
| --- | --- |
107+
| `assertThat(list.size()).isEqualTo(N)` | `assertThat(list).hasSize(N)` |
108+
| `assertThat(list.isEmpty()).isTrue()` / `.hasSize(0)` | `assertThat(list).isEmpty()` |
109+
| `assertThat(list.contains(x)).isTrue()` | `assertThat(list).contains(x)` |
110+
| per-index `get(i)` checks of every element | `assertThat(list).containsExactly(a, b, ...)` |
111+
112+
`containsExactly` already verifies size, so a separate `hasSize` is redundant.
113+
Same shape applies to `String.length()`, `Map.size()`, and `array.length`
114+
`assertThat(...).hasSize(N)`.
115+
116+
## [Testing] Span Attribute Assertions
117+
118+
- Prefer `hasAttributesSatisfyingExactly(...)` over `hasAttributesSatisfying(...)`
119+
— the non-exact variant **silently ignores unexpected attributes**. Also
120+
prefer it over `hasAttributes(...)` for consistency.
121+
- For zero-attribute span assertions, use `hasTotalAttributeCount(0)`.
122+
- `hasTotalAttributeCount(...)` paired with `hasAttributesSatisfyingExactly(...)`
123+
is redundant — the exact variant already validates the count. Remove the
124+
count call.
125+
- Metric points are different: there is no `hasTotalAttributeCount(...)` on
126+
metric points, so use `point.hasAttributes(Attributes.empty())` for empty
127+
metric-point checks.
128+
- Do not introduce redundant `(long)` casts in `equalTo(longKey(...), value)`
129+
when `value` is already an `int` — the `equalTo(AttributeKey<Long>, int)`
130+
overload exists.
131+
132+
## [Testing] `satisfies()` Lambda Parameters
133+
134+
Inside a `satisfies(AttributeKey, lambda)` attribute-assertion the lambda
135+
parameter is an `AbstractAssert` (e.g. `AbstractStringAssert<?>`), not the raw
136+
value. Fluent calls like `taskId.contains(jobName)` are already proper
137+
assertions — do **not** wrap them in `assertThat(value.contains(x)).isTrue()`,
138+
which degrades the failure message.
139+
140+
Name the outer parameter `val` in Java (or `value` in Scala, where `val` is
141+
reserved). Use `v` only for a nested inner-lambda parameter.
142+
143+
This guidance applies only to attribute-assertion `satisfies(...)`; for
144+
`span.satisfies(...)`, `point.satisfies(...)`, etc. use a descriptive name
145+
(`spanData`, `pointData`, `result`).
146+
147+
## [Javaagent] Singleton Accessor Naming
148+
149+
In `*Singletons`, `*SpanNaming`, and similar holder classes, zero-arg accessor
150+
methods that **directly return a stored singleton field** must match the field
151+
name with no `get` prefix:
152+
153+
```java
154+
private static final Instrumenter<Request, Response> instrumenter = ...;
155+
156+
public static Instrumenter<Request, Response> instrumenter() {
157+
return instrumenter;
158+
}
159+
```
160+
161+
- Methods that take arguments or compute a value are not singleton accessors —
162+
keep their normal names (including `get*` when appropriate). Do not flag
163+
`getAddressAndPort(client)` on this basis.
164+
- Uppercase constant-like fields (e.g. `VirtualField`, `ContextKey`) may be
165+
exposed as `public static final` directly with no accessor.
166+
- Caller sites should static-import the accessor / constant and call it
167+
unqualified.
168+
169+
## [General] Engineering Correctness
170+
171+
Flag real defects on changed lines: logic errors, concurrency hazards, resource
172+
leaks, copy/paste mistakes, incorrect comments, unsafe error handling, dead
173+
code, security regressions. Skip stylistic preferences not listed above.

AGENTS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,16 @@
22

33
Read [CONTRIBUTING.md](CONTRIBUTING.md) first. It is the source of truth for repository layout,
44
build and test commands, style expectations, and scope.
5+
6+
## Knowledge Loading
7+
8+
For coding, fix, and refactoring tasks, consult `.github/agents/knowledge/README.md`
9+
and load only the article(s) relevant to the current task.
10+
11+
## Gradle Execution Rules
12+
13+
- Never use `--rerun-tasks`. Use `--rerun` when needed.
14+
- Builds and tests can take several minutes. Run Gradle with timeout `0` and wait.
15+
Slow output is not a hang.
16+
- Never pipe Gradle output through `tail`, `head`, `grep`, etc. Piping masks the
17+
Gradle exit code.

0 commit comments

Comments
 (0)