1// Copyright 2018 The Go Cloud Development Kit Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package sdserver provides the diagnostic hooks for a server using
16// Stackdriver.
17package sdserver // import "gocloud.dev/server/sdserver"
18
19import (
20	"fmt"
21	"os"
22
23	"github.com/google/wire"
24	"gocloud.dev/gcp"
25	"gocloud.dev/internal/useragent"
26	"gocloud.dev/server"
27	"gocloud.dev/server/requestlog"
28
29	"contrib.go.opencensus.io/exporter/stackdriver"
30	"contrib.go.opencensus.io/exporter/stackdriver/monitoredresource"
31	"go.opencensus.io/trace"
32	"golang.org/x/oauth2"
33	"google.golang.org/api/option"
34)
35
36// Set is a Wire provider set that provides the diagnostic hooks for
37// *server.Server given a GCP token source and a GCP project ID.
38var Set = wire.NewSet(
39	server.Set,
40	NewExporter,
41	monitoredresource.Autodetect,
42	wire.Bind(new(trace.Exporter), new(*stackdriver.Exporter)),
43	NewRequestLogger,
44	wire.Bind(new(requestlog.Logger), new(*requestlog.StackdriverLogger)),
45)
46
47// NewExporter returns a new OpenCensus Stackdriver exporter.
48//
49// The second return value is a Wire cleanup function that calls Flush
50// on the exporter.
51func NewExporter(id gcp.ProjectID, ts gcp.TokenSource, mr monitoredresource.Interface) (*stackdriver.Exporter, func(), error) {
52	opts := []option.ClientOption{
53		option.WithTokenSource(oauth2.TokenSource(ts)),
54		useragent.ClientOption("server"),
55	}
56	exp, err := stackdriver.NewExporter(stackdriver.Options{
57		ProjectID:               string(id),
58		MonitoringClientOptions: opts,
59		TraceClientOptions:      opts,
60		MonitoredResource:       mr,
61	})
62	if err != nil {
63		return nil, nil, err
64	}
65
66	return exp, func() { exp.Flush() }, err
67}
68
69// NewRequestLogger returns a request logger that sends entries to stdout.
70func NewRequestLogger() *requestlog.StackdriverLogger {
71	// For now, request logs are written to stdout and get picked up by fluentd.
72	// This also works when running locally.
73	return requestlog.NewStackdriverLogger(os.Stdout, func(e error) { fmt.Println(e) })
74}
75