Repository: open-telemetry/opentelemetry-go (Go)

Issue:
Log an error for empty view criteria
The [specification](https://github.com/open-telemetry/opentelemetry-specification/blob/0c5bfa999a5310801d5c36d2a82cbcd0e32ca9cb/specification/metrics/sdk.md#view) recommends:

>   * If no criteria is provided, the SDK SHOULD treat it as an error. It is recommended that the SDK implementations fail fast. Please refer to [Error handling in OpenTelemetry](../error-handling.md) for the general guidance.

This is not treated as an error:

https://github.com/open-telemetry/opentelemetry-go/blob/b2246d58650bc6db04459353843250ee3bba77fc/sdk/metric/view.go#L57-L59

An error should be logged to match the other existing error already logged by `NewView`:

https://github.com/open-telemetry/opentelemetry-go/blob/b2246d58650bc6db04459353843250ee3bba77fc/sdk/metric/view.go#L94-L98

_Originally posted by @MrAlias in https://github.com/open-telemetry/opentelemetry-go/issues/3645#issuecomment-1569121108_
            


Discussion: > An error should be logged 

Why not returning an error as suggested per the specification? I would consider changing the declaration to:

```go
func NewView(criteria Instrument, mask Stream) (View, error) {
```

1. We still can return a view when a error is reported
2. I guess usually the operators (users) do not want such errors and would prefer to react. In some cases they may even want to crash the app if they find that they do not accept  a misconfigured View. 
Returning an error means `NewView` will not be able to be passed directly to `WithView`.
> Returning an error means `NewView` will not be able to be passed directly to `WithView`.

That is the reason we already log an error with the global logger. It makes sense to keep the pattern here.
On the other hand, the exporter factory functions like [`otlpmetrichttp.New`](https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp#New) are returning `(metric.Exporter, error)` so that one cannot directly pass the result to [`metric.NewPeriodicReader`](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric#NewPeriodicReader).

I see Go as a quite verbose language when it comes to error handling. I do not feel that "fluent-like" API is idiomatic. The user can always create a helper that would handle the error (e.g. log, ignore, panic).
I don't follow. You are suggesting that precedence from a different function from a different package from a different part of the setup should take precedence for `NewView`? A function with existing precedence for error handling?
That is only "one" reason out of three.

1. I feel that explicit error handling is more idiomatic
2. It would literally follow the OTel Specification recommendation
3. Precedence from a different package

(in this order)



Fix (patch):
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2f69a0ddfd6..8759f726a18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,6 +33,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 ### Fixed
 
 - Correctly format log messages from the `go.opentelemetry.io/otel/exporters/zipkin` exporter. (#4143)
+- Log an error for calls to `NewView` in `go.opentelemetry.io/otel/sdk/metric` that have empty criteria. (#4307)
 
 ## [1.16.0/0.39.0] 2023-05-18
 
diff --git a/sdk/metric/view.go b/sdk/metric/view.go
index 9dab839f003..f1df24466bc 100644
--- a/sdk/metric/view.go
+++ b/sdk/metric/view.go
@@ -25,6 +25,7 @@ import (
 
 var (
 	errMultiInst = errors.New("name replacement for multiple instruments")
+	errEmptyView = errors.New("no criteria provided for view")
 
 	emptyView = func(Instrument) (Stream, bool) { return Stream{}, false }
 )
@@ -55,6 +56,10 @@ type View func(Instrument) (Stream, bool)
 // View, create a View directly.
 func NewView(criteria Instrument, mask Stream) View {
 	if criteria.empty() {
+		global.Error(
+			errEmptyView, "dropping view",
+			"mask", mask,
+		)
 		return emptyView
 	}