Skip to content

Conversation

@lightsta1ker
Copy link

Addresses #7937

@lightsta1ker lightsta1ker changed the title [WIP] Updating uninstrumented dice example [WIP] Updating dice example based on Updated Specification for the reference application Oct 30, 2025
@lightsta1ker lightsta1ker marked this pull request as ready for review October 30, 2025 17:43
@lightsta1ker lightsta1ker requested a review from a team as a code owner October 30, 2025 17:43
@lightsta1ker lightsta1ker changed the title [WIP] Updating dice example based on Updated Specification for the reference application Updating dice example based on Updated Specification for the reference application Oct 31, 2025
@pellared
Copy link
Member

pellared commented Nov 4, 2025

@lightsta1ker, I won't have time to review it further until I am back from KubeCon NA. Hopefully other @open-telemetry/go-approvers are going to help with reviews.

@lightsta1ker
Copy link
Author

Sure, @pellared . Thank you for the review & suggestions!

"encoding/json"
"errors"
"log"
"math/rand"
Copy link
Member

Choose a reason for hiding this comment

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

We can use math/rand/v2

@pellared

This comment was marked as resolved.

@lightsta1ker

This comment was marked as resolved.

Copy link
Member

@flc1125 flc1125 left a comment

Choose a reason for hiding this comment

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

The normative review is completed, with additional notes:

According to the specification requirements, support for the OTLP exporter is needed. Currently, this part is not yet supported, but I believe it can be fully implemented through a separate PR.

@flc1125
Copy link
Member

flc1125 commented Nov 11, 2025

@lightsta1ker We still have some issues to resolve, including CI checks.

@lightsta1ker
Copy link
Author

@flc1125 I thought those checks were not relevant to this PR as it's not customer facing.

@pellared
Copy link
Member

@flc1125 I thought those checks were not relevant to this PR as it's not customer facing.

They are relevant.

@lightsta1ker
Copy link
Author

Updated with fixes for failing lint checks and error handling. Also rebased.

@lightsta1ker
Copy link
Author

@pellared Is changelog needed?

@pellared
Copy link
Member

@pellared Is changelog needed?

No

@pellared pellared added the Skip Changelog Allow PR to succeed without requiring an addition to the CHANGELOG label Nov 19, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR updates the dice example application to align with the updated specification for the OpenTelemetry reference application. The changes modernize the API design, improve observability instrumentation, and add configurable deployment options.

Key Changes

  • Refactored HTTP handler to use query parameters (rolls and player) instead of path parameters, with JSON responses
  • Enhanced OpenTelemetry instrumentation with additional metrics (histogram for dice outcomes, gauge for last rolls value) and proper resource configuration
  • Added configurable port via APPLICATION_PORT environment variable for flexible deployment

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
examples/dice/uninstrumented/rolldice.go Refactored handler to parse query params, return JSON responses, added input validation with max rolls limit, and separated concerns with helper functions
examples/dice/uninstrumented/main.go Added configurable port support and updated route registration to single /rolldice endpoint
examples/dice/instrumented/rolldice.go Applied same refactoring as uninstrumented version, upgraded to math/rand/v2, added histogram and gauge metrics, improved telemetry context propagation
examples/dice/instrumented/otel.go Added resource configuration with environment, process, host, and SDK information; updated all provider constructors to accept resource parameter
examples/dice/instrumented/main.go Added configurable port support and simplified route registration to single endpoint

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@pellared
Copy link
Member

@open-telemetry/go-approvers, anyone has some time to review this PR?

Co-authored-by: Damien Mathieu <42@dmathieu.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

func writeJSON(w http.ResponseWriter, v any) {
data, err := json.Marshal(v)
if err != nil {
w.Header().Set("Content-Type", "application/json")
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The Content-Type header is set after WriteHeader is called. Headers must be set before calling WriteHeader to ensure they are properly sent in the response.

Copilot uses AI. Check for mistakes.
Comment on lines +160 to +161
results := make([]int, rolls)
for i := range rolls {
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The uninstrumented version has special handling when rolls==1 (lines 88-89) that returns early without allocating a slice and using a loop. However, the instrumented version doesn't have this optimization and always allocates a slice and uses a loop even for a single roll. This creates an inconsistency in behavior between the two versions.

Suggested change
results := make([]int, rolls)
for i := range rolls {
if rolls == 1 {
// Fast path for a single roll to mirror the uninstrumented implementation.
result := rollOnce(ctx)
outcomeHist.Record(ctx, int64(result))
rollsAttr := attribute.Int("rolls", rolls)
span.SetAttributes(rollsAttr)
rollCnt.Add(ctx, int64(rolls), metric.WithAttributes(rollsAttr))
lastRolls.Store(int64(rolls))
return []int{result}, nil
}
results := make([]int, rolls)
for i := range results {

Copilot uses AI. Check for mistakes.
logger.DebugContext(r.Context(), "player rolled dice", "player", player, "results", results)
}
logger.InfoContext(ctx, msg, "result", roll)
logger.InfoContext(r.Context(), "Some player rolled a dice.")
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The log message "Some player rolled a dice." is vague and doesn't provide useful information. The DEBUG logs above (lines 111-113) already capture the actual roll information with player details and results. This INFO log should either be removed or made more informative, such as including the HTTP method and URL like the uninstrumented version does at line 51.

Suggested change
logger.InfoContext(r.Context(), "Some player rolled a dice.")
logger.InfoContext(r.Context(), "player rolled dice request", "method", r.Method, "url", r.URL.String())

Copilot uses AI. Check for mistakes.
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
msg := "Internal server error"
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The error message is inconsistent between instrumented and uninstrumented versions. The uninstrumented version returns a detailed error message from the rollDice function (e.g., "rolls parameter exceeds maximum allowed value"), while the instrumented version returns a generic "Internal server error" message. This reduces the usefulness of error responses for API consumers.

Suggested change
msg := "Internal server error"
msg := err.Error()

Copilot uses AI. Check for mistakes.
logger.InfoContext(ctx, msg, "result", roll)
logger.InfoContext(r.Context(), "Some player rolled a dice.")

w.Header().Set("Content-Type", "application/json")
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The Content-Type header is set twice for successful responses - once at line 117 before calling writeJSON, and again inside writeJSON at line 72. The duplicate header setting at line 117 should be removed since writeJSON already sets it.

Suggested change
w.Header().Set("Content-Type", "application/json")

Copilot uses AI. Check for mistakes.
_, span := tracer.Start(ctx, "rollOnce")
defer span.End()

roll := 1 + rand.IntN(6) //nolint:gosec // G404: Use of weak random number generator (math/rand instead of crypto/rand) is ignored as this is not security-sensitive.
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The instrumented version uses math/rand/v2 and rand.IntN, while the uninstrumented version uses math/rand and rand.Intn. For consistency and to serve as a proper reference example, both versions should use the same random number generation approach.

Copilot uses AI. Check for mistakes.

results, err := rolldice(rolls)
if err != nil {
w.Header().Set("Content-Type", "application/json")
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The Content-Type header is set after WriteHeader is called. Headers should be set before calling WriteHeader, otherwise they may not be properly sent in the response.

Copilot uses AI. Check for mistakes.

// Check if rolls is a number.
rolls, err := strconv.Atoi(rollsParam)
if err != nil {
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

Missing Content-Type header before WriteHeader. The header should be set before calling WriteHeader to ensure it's properly included in the response. This is inconsistent with how the instrumented version handles this at line 86-87, and with how other error paths in this file handle it.

Suggested change
if err != nil {
if err != nil {
w.Header().Set("Content-Type", "application/json")

Copilot uses AI. Check for mistakes.
results, err := rolldice(rolls)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

Missing JSON response body for the error. When rolldice returns an error, the response should include a JSON error message body like other error paths in this handler do (e.g., lines 30-32). Currently, it only sets headers and returns, resulting in an empty response body.

Suggested change
w.WriteHeader(http.StatusInternalServerError)
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(map[string]string{
"status": "error",
"message": "Internal Server Error",
})

Copilot uses AI. Check for mistakes.
Comment on lines +128 to +129
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
Copy link

Copilot AI Jan 9, 2026

Choose a reason for hiding this comment

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

The Content-Type header is set after WriteHeader is called. Headers should be set before calling WriteHeader to ensure they are properly sent in the response.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Skip Changelog Allow PR to succeed without requiring an addition to the CHANGELOG

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants