Skip to content

Commit

Permalink
feat(bigtable): Wrapping errors on Export (#10836)
Browse files Browse the repository at this point in the history
* test(bigtable): Adding tests to verify prefix
  • Loading branch information
bhshkh committed Sep 9, 2024
1 parent 9a94ff8 commit fc6d6a8
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
2 changes: 1 addition & 1 deletion bigtable/metrics_monitoring_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (me *monitoringExporter) Export(ctx context.Context, rm *otelmetricdata.Res
default:
}

return me.exportTimeSeries(ctx, rm)
return wrapMetricsError(me.exportTimeSeries(ctx, rm))
}

// Temporality returns the Temporality to use for an instrument kind.
Expand Down
87 changes: 87 additions & 0 deletions bigtable/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,21 @@ limitations under the License.
package bigtable

import (
"bytes"
"context"
"encoding/base64"
"fmt"
"io"
"sort"
"strings"
"sync"
"testing"
"time"

btpb "cloud.google.com/go/bigtable/apiv2/bigtablepb"
"cloud.google.com/go/internal/testutil"
"github.com/google/go-cmp/cmp/cmpopts"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"google.golang.org/api/option"
"google.golang.org/grpc"
Expand Down Expand Up @@ -277,6 +281,89 @@ func TestNewBuiltinMetricsTracerFactory(t *testing.T) {
}
}

func setMockErrorHandler(t *testing.T, mockErrorHandler *MockErrorHandler) {
origErrHandler := otel.GetErrorHandler()
otel.SetErrorHandler(mockErrorHandler)
t.Cleanup(func() {
otel.SetErrorHandler(origErrHandler)
})
}

func TestExporterLogs(t *testing.T) {
ctx := context.Background()
project := "test-project"
instance := "test-instance"

// Reduce sampling period to reduce test run time
origSamplePeriod := defaultSamplePeriod
defaultSamplePeriod = 5 * time.Second
defer func() {
defaultSamplePeriod = origSamplePeriod
}()

tbl, cleanup, gotErr := setupFakeServer(project, instance, ClientConfig{})
t.Cleanup(func() { defer cleanup() })
if gotErr != nil {
t.Fatalf("err: got: %v, want: %v", gotErr, nil)
return
}

// Set up mock error handler
mer := &MockErrorHandler{
buffer: new(bytes.Buffer),
}
setMockErrorHandler(t, mer)

// record start time
testStartTime := time.Now()

// Perform read rows operation
tbl.ReadRows(ctx, NewRange("a", "z"), func(r Row) bool {
return true
})

// Calculate elapsed time
elapsedTime := time.Since(testStartTime)
if elapsedTime < 3*defaultSamplePeriod {
// Ensure at least 2 datapoints are recorded
time.Sleep(3*defaultSamplePeriod - elapsedTime)
}

// In setupFakeServer above, Bigtable client is created with options :
// option.WithGRPCConn(conn), option.WithGRPCDialOption(grpc.WithBlock())
// These same options will be used to create Monitoring client but since there
// is no fake Monitoring server at that grpc conn, all the exports result in failure.
// Thus, there should be errors in errBuf.
data, readErr := mer.read()
if readErr != nil {
t.Errorf("Failed to read errBuf: %v", readErr)
}
if !strings.Contains(data, metricsErrorPrefix) {
t.Errorf("Expected %v to contain %v", data, metricsErrorPrefix)
}
}

type MockErrorHandler struct {
buffer *bytes.Buffer
bufferMutex sync.Mutex
}

func (m *MockErrorHandler) Handle(err error) {
m.bufferMutex.Lock()
defer m.bufferMutex.Unlock()
fmt.Fprintln(m.buffer, err)
}

func (m *MockErrorHandler) read() (string, error) {
m.bufferMutex.Lock()
defer m.bufferMutex.Unlock()
data, err := io.ReadAll(m.buffer)
if err != nil {
return "", err
}
return string(data), nil
}

func TestToOtelMetricAttrs(t *testing.T) {
mt := builtinMetricsTracer{
tableName: "my-table",
Expand Down

0 comments on commit fc6d6a8

Please sign in to comment.