• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19996

24 Sep 2025 12:08AM UTC coverage: 88.575% (+0.03%) from 88.543%
#19996

push

github

web-flow
Implement otel retry metrics (#12064)

implements [A96](https://github.com/grpc/proposal/pull/488/files)

34731 of 39211 relevant lines covered (88.57%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.11
/../api/src/main/java/io/grpc/ClientStreamTracer.java
1
/*
2
 * Copyright 2017 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.common.base.MoreObjects;
22
import javax.annotation.concurrent.ThreadSafe;
23

24
/**
25
 * {@link StreamTracer} for the client-side.
26
 */
27
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/2861")
28
@ThreadSafe
29
public abstract class ClientStreamTracer extends StreamTracer {
1✔
30
  /**
31
   * Indicates how long the call was delayed, in nanoseconds, due to waiting for name resolution
32
   * result. If the call option is not set, the call did not experience name resolution delay.
33
   */
34
  public static final CallOptions.Key<Long> NAME_RESOLUTION_DELAYED =
1✔
35
      CallOptions.Key.create("io.grpc.ClientStreamTracer.NAME_RESOLUTION_DELAYED");
1✔
36

37
  /**
38
   * The stream is being created on a ready transport.
39
   *
40
   * @param headers the mutable initial metadata. Modifications to it will be sent to the socket but
41
   *     not be seen by client interceptors and the application.
42
   *
43
   * @since 1.40.0
44
   */
45
  public void streamCreated(@Grpc.TransportAttr Attributes transportAttrs, Metadata headers) {
46
  }
1✔
47

48
  /**
49
   * Name resolution is completed and the connection starts getting established. This method is only
50
   * invoked on the streams that encounter such delay.
51
   *
52
   * </p>gRPC buffers the client call if the remote address and configurations, e.g. timeouts and
53
   * retry policy, are not ready. Asynchronously gRPC internally does the name resolution to get
54
   * this information. The streams that are processed immediately on ready transports by the time
55
   * the RPC comes do not go through the pending process, thus this callback will not be invoked.
56
   */
57
  public void createPendingStream() {
58
  }
1✔
59

60
  /**
61
   * Headers has been sent to the socket.
62
   */
63
  public void outboundHeaders() {
64
  }
1✔
65

66
  /**
67
   * Headers has been received from the server.
68
   */
69
  public void inboundHeaders() {
70
  }
1✔
71

72
  /**
73
   * Headers has been received from the server. This method does not pass ownership to {@code
74
   * headers}, so implementations must not access the metadata after returning. Modifications to the
75
   * metadata within this method will be seen by interceptors and the application.
76
   *
77
   * @param headers the received header metadata
78
   */
79
  public void inboundHeaders(Metadata headers) {
80
    inboundHeaders();
1✔
81
  }
1✔
82

83
  /**
84
   * Trailing metadata has been received from the server. This method does not pass ownership to
85
   * {@code trailers}, so implementations must not access the metadata after returning.
86
   * Modifications to the metadata within this method will be seen by interceptors and the
87
   * application.
88
   *
89
   * @param trailers the received trailing metadata
90
   * @since 1.17.0
91
   */
92
  public void inboundTrailers(Metadata trailers) {
93
  }
1✔
94

95
  /**
96
   * Information providing context to the call became available.
97
   */
98
  @Internal
99
  public void addOptionalLabel(String key, String value) {
100
  }
1✔
101

102
  /**
103
   * Factory class for {@link ClientStreamTracer}.
104
   */
105
  public abstract static class Factory {
1✔
106
    /**
107
     * Creates a {@link ClientStreamTracer} for a new client stream.  This is called inside the
108
     * transport when it's creating the stream.
109
     *
110
     * @param info information about the stream
111
     * @param headers the mutable headers of the stream. It can be safely mutated within this
112
     *        method.  Changes made to it will be sent by the stream.  It should not be saved
113
     *        because it is not safe for read or write after the method returns.
114
     *
115
     * @since 1.20.0
116
     */
117
    public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) {
118
      throw new UnsupportedOperationException("Not implemented");
×
119
    }
120
  }
121

122
  /**
123
   * Information about a stream.
124
   *
125
   * <p>Note this class doesn't override {@code equals()} and {@code hashCode}, as is the case for
126
   * {@link CallOptions}.
127
   *
128
   * @since 1.20.0
129
   */
130
  @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2861")
131
  public static final class StreamInfo {
132
    private final CallOptions callOptions;
133
    private final int previousAttempts;
134
    private final boolean isTransparentRetry;
135
    private final boolean isHedging;
136

137
    StreamInfo(
138
        CallOptions callOptions, int previousAttempts, boolean isTransparentRetry,
139
        boolean isHedging) {
1✔
140
      this.callOptions = checkNotNull(callOptions, "callOptions");
1✔
141
      this.previousAttempts = previousAttempts;
1✔
142
      this.isTransparentRetry = isTransparentRetry;
1✔
143
      this.isHedging = isHedging;
1✔
144
    }
1✔
145

146
    /**
147
     * Returns the effective CallOptions of the call.
148
     */
149
    public CallOptions getCallOptions() {
150
      return callOptions;
1✔
151
    }
152

153
    /**
154
     * Returns the number of preceding attempts for the RPC.
155
     *
156
     * @since 1.40.0
157
     */
158
    public int getPreviousAttempts() {
159
      return previousAttempts;
1✔
160
    }
161

162
    /**
163
     * Whether the stream is a transparent retry.
164
     *
165
     * @since 1.40.0
166
     */
167
    public boolean isTransparentRetry() {
168
      return isTransparentRetry;
1✔
169
    }
170

171
    /**
172
     * Whether the stream is hedging.
173
     *
174
     * @since 1.74.0
175
     */
176
    public boolean isHedging() {
177
      return isHedging;
1✔
178
    }
179

180
    /**
181
     * Converts this StreamInfo into a new Builder.
182
     *
183
     * @since 1.21.0
184
     */
185
    public Builder toBuilder() {
186
      return new Builder()
1✔
187
          .setCallOptions(callOptions)
1✔
188
          .setPreviousAttempts(previousAttempts)
1✔
189
          .setIsTransparentRetry(isTransparentRetry)
1✔
190
          .setIsHedging(isHedging);
1✔
191

192
    }
193

194
    /**
195
     * Creates an empty Builder.
196
     *
197
     * @since 1.21.0
198
     */
199
    public static Builder newBuilder() {
200
      return new Builder();
1✔
201
    }
202

203
    @Override
204
    public String toString() {
205
      return MoreObjects.toStringHelper(this)
×
206
          .add("callOptions", callOptions)
×
207
          .add("previousAttempts", previousAttempts)
×
208
          .add("isTransparentRetry", isTransparentRetry)
×
209
          .add("isHedging", isHedging)
×
210
          .toString();
×
211
    }
212

213
    /**
214
     * Builds {@link StreamInfo} objects.
215
     *
216
     * @since 1.21.0
217
     */
218
    public static final class Builder {
219
      private CallOptions callOptions = CallOptions.DEFAULT;
1✔
220
      private int previousAttempts;
221
      private boolean isTransparentRetry;
222
      private boolean isHedging;
223

224
      Builder() {
1✔
225
      }
1✔
226

227
      /**
228
       * Sets the effective CallOptions of the call.  This field is optional.
229
       */
230
      public Builder setCallOptions(CallOptions callOptions) {
231
        this.callOptions = checkNotNull(callOptions, "callOptions cannot be null");
1✔
232
        return this;
1✔
233
      }
234

235
      /**
236
       * Set the number of preceding attempts of the RPC.
237
       *
238
       * @since 1.40.0
239
       */
240
      public Builder setPreviousAttempts(int previousAttempts) {
241
        this.previousAttempts = previousAttempts;
1✔
242
        return this;
1✔
243
      }
244

245
      /**
246
       * Sets whether the stream is a transparent retry.
247
       *
248
       * @since 1.40.0
249
       */
250
      public Builder setIsTransparentRetry(boolean isTransparentRetry) {
251
        this.isTransparentRetry = isTransparentRetry;
1✔
252
        return this;
1✔
253
      }
254

255
      /**
256
       * Sets whether the stream is hedging.
257
       *
258
       * @since 1.74.0
259
       */
260
      public Builder setIsHedging(boolean isHedging) {
261
        this.isHedging = isHedging;
1✔
262
        return this;
1✔
263
      }
264

265
      /**
266
       * Builds a new StreamInfo.
267
       */
268
      public StreamInfo build() {
269
        return new StreamInfo(callOptions, previousAttempts, isTransparentRetry, isHedging);
1✔
270
      }
271
    }
272
  }
273
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc