Skip to content

Commit

Permalink
feat: Allow setting of application name to the User-Agent header value
Browse files Browse the repository at this point in the history
  • Loading branch information
vlastahajek committed Oct 25, 2022
1 parent e52048f commit 4a444de
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 9 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
## [unreleased]
### Features
- [#358](https://github.com/influxdata/influxdb-client-go/pull/358):
- Added possibility to set an application name, which will be part of the User-Agent HTTP header
- Set using `Options.SetApplicationName`
- Error message is written to log if an application name is not set.
- Added example how to fully override `User-Agent` header using `Doer` interface

### Bug fixes
- [#359](https://github.com/influxdata/influxdb-client-go/pull/359) `WriteAPIBlocking.Flush()` correctly returns nil error.

Expand Down
13 changes: 13 additions & 0 deletions api/http/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Options struct {
tlsConfig *tls.Config
// HTTP request timeout in sec. Default 20
httpRequestTimeout uint
// Application name in the User-Agent HTTP header string
appName string
}

// HTTPClient returns the http.Client that is configured to be used
Expand Down Expand Up @@ -119,6 +121,17 @@ func (o *Options) SetHTTPRequestTimeout(httpRequestTimeout uint) *Options {
return o
}

// ApplicationName returns application name used in the User-Agent HTTP header
func (o *Options) ApplicationName() string {
return o.appName
}

// SetApplicationName sets an application name to the User-Agent HTTP header
func (o *Options) SetApplicationName(appName string) *Options {
o.appName = appName
return o
}

// DefaultOptions returns Options object with default values
func DefaultOptions() *Options {
return &Options{httpRequestTimeout: 20}
Expand Down
5 changes: 4 additions & 1 deletion api/http/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestDefaultOptions(t *testing.T) {
assert.Equal(t, uint(20), opts.HTTPRequestTimeout())
assert.NotNil(t, opts.HTTPClient())
assert.True(t, opts.OwnHTTPClient())
assert.EqualValues(t, "", opts.ApplicationName())
}

func TestOptionsSetting(t *testing.T) {
Expand All @@ -28,9 +29,11 @@ func TestOptionsSetting(t *testing.T) {
}
opts := http.DefaultOptions().
SetTLSConfig(tlsConfig).
SetHTTPRequestTimeout(50)
SetHTTPRequestTimeout(50).
SetApplicationName("Monitor/1.1")
assert.Equal(t, tlsConfig, opts.TLSConfig())
assert.Equal(t, uint(50), opts.HTTPRequestTimeout())
assert.EqualValues(t, "Monitor/1.1", opts.ApplicationName())
if client := opts.HTTPClient(); assert.NotNil(t, client) {
assert.Equal(t, 50*time.Second, client.Timeout)
assert.Equal(t, tlsConfig, client.Transport.(*nethttp.Transport).TLSClientConfig)
Expand Down
4 changes: 3 additions & 1 deletion api/http/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type service struct {
serverURL string
authorization string
client Doer
userAgent string
}

// NewService creates instance of http Service with given parameters
Expand All @@ -73,6 +74,7 @@ func NewService(serverURL, authorization string, httpOptions *Options) Service {
serverURL: serverURL,
authorization: authorization,
client: httpOptions.HTTPDoer(),
userAgent: http2.FormatUserAgent(httpOptions.ApplicationName()),
}
}

Expand Down Expand Up @@ -128,7 +130,7 @@ func (s *service) DoHTTPRequestWithResponse(req *http.Request, requestCallback R
req.Header.Set("Authorization", s.authorization)
}
if req.Header.Get("User-Agent") == "" {
req.Header.Set("User-Agent", http2.UserAgent)
req.Header.Set("User-Agent", s.userAgent)
}
if requestCallback != nil {
requestCallback(req)
Expand Down
3 changes: 1 addition & 2 deletions api/writeAPIBlocking.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,8 @@ func (w *writeAPIBlocking) write(ctx context.Context, line string) error {
w.batch = append(w.batch, line)
if len(w.batch) == int(w.writeOptions.BatchSize()) {
return w.flush(ctx)
} else {
return nil
}
return nil
}
err := w.service.WriteBatch(ctx, iwrite.NewBatch(line, w.writeOptions.MaxRetryTime()))
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ func NewClientWithOptions(serverURL string, authToken string, options *Options)
}
ilog.Infof("Using URL '%s'%s", serverURL, tokenStr)
}
if options.ApplicationName() == "" {
ilog.Error("Application name is not set")
}
return client
}

Expand Down
58 changes: 57 additions & 1 deletion client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ package influxdb2
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httptest"
"runtime"
"strings"
"testing"
"time"

ihttp "github.com/influxdata/influxdb-client-go/v2/api/http"
"github.com/influxdata/influxdb-client-go/v2/domain"
http2 "github.com/influxdata/influxdb-client-go/v2/internal/http"
iwrite "github.com/influxdata/influxdb-client-go/v2/internal/write"
Expand Down Expand Up @@ -76,24 +80,76 @@ func TestWriteAPIManagement(t *testing.T) {
assert.Len(t, c.syncWriteAPIs, 0)
}

func TestUserAgentBase(t *testing.T) {
ua := fmt.Sprintf("influxdb-client-go/%s (%s; %s)", Version, runtime.GOOS, runtime.GOARCH)
assert.Equal(t, ua, http2.UserAgentBase)

}

type doer struct {
userAgent string
doer ihttp.Doer
}

func (d *doer) Do(req *http.Request) (*http.Response, error) {
req.Header.Set("User-Agent", d.userAgent)
return d.doer.Do(req)
}

func TestUserAgent(t *testing.T) {
ua := http2.UserAgentBase
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
<-time.After(100 * time.Millisecond)
if r.Header.Get("User-Agent") == http2.UserAgent {
if r.Header.Get("User-Agent") == ua {
w.WriteHeader(http.StatusNoContent)
} else {
w.WriteHeader(http.StatusNotFound)
}
}))

defer server.Close()
var sb strings.Builder
log.SetOutput(&sb)
log.SetFlags(0)
c := NewClient(server.URL, "x")
assert.True(t, strings.Contains(sb.String(), "Application name is not set"))
up, err := c.Ping(context.Background())
require.NoError(t, err)
assert.True(t, up)

err = c.WriteAPIBlocking("o", "b").WriteRecord(context.Background(), "a,a=a a=1i")
assert.NoError(t, err)

c.Close()
sb.Reset()
// Test setting application name
c = NewClientWithOptions(server.URL, "x", DefaultOptions().SetApplicationName("Monitor/1.1"))
ua = fmt.Sprintf("influxdb-client-go/%s (%s; %s) Monitor/1.1", Version, runtime.GOOS, runtime.GOARCH)
assert.False(t, strings.Contains(sb.String(), "Application name is not set"))
up, err = c.Ping(context.Background())
require.NoError(t, err)
assert.True(t, up)

err = c.WriteAPIBlocking("o", "b").WriteRecord(context.Background(), "a,a=a a=1i")
assert.NoError(t, err)
c.Close()

ua = "Monitor/1.1"
opts := DefaultOptions()
opts.HTTPOptions().SetHTTPDoer(&doer{
userAgent: ua,
doer: http.DefaultClient,
})

//Create client with custom user agent setter
c = NewClientWithOptions(server.URL, "x", opts)
up, err = c.Ping(context.Background())
require.NoError(t, err)
assert.True(t, up)

err = c.WriteAPIBlocking("o", "b").WriteRecord(context.Background(), "a,a=a a=1i")
assert.NoError(t, err)
c.Close()
}

func TestServerError429(t *testing.T) {
Expand Down
16 changes: 14 additions & 2 deletions internal/http/userAgent.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,17 @@
// Package http hold internal HTTP related stuff
package http

// UserAgent keeps once created User-Agent string
var UserAgent string
import (
"fmt"
)

// UserAgentBase keeps once created base User-Agent string
var UserAgentBase string

// FormatUserAgent creates User-Agent header value for application name
func FormatUserAgent(appName string) string {
if appName != "" {
return fmt.Sprintf("%s %s", UserAgentBase, appName)
}
return UserAgentBase
}
11 changes: 11 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,17 @@ func (o *Options) AddDefaultTag(key, value string) *Options {
return o
}

// ApplicationName returns application name used in the User-Agent HTTP header
func (o *Options) ApplicationName() string {
return o.HTTPOptions().ApplicationName()
}

// SetApplicationName sets an application name to the User-Agent HTTP header
func (o *Options) SetApplicationName(appName string) *Options {
o.HTTPOptions().SetApplicationName(appName)
return o
}

// DefaultOptions returns Options object with default values
func DefaultOptions() *Options {
return &Options{logLevel: 0, writeOptions: write.DefaultOptions(), httpOptions: http.DefaultOptions()}
Expand Down
5 changes: 4 additions & 1 deletion options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func TestDefaultOptions(t *testing.T) {
assert.EqualValues(t, (*tls.Config)(nil), opts.TLSConfig())
assert.EqualValues(t, 20, opts.HTTPRequestTimeout())
assert.EqualValues(t, 0, opts.LogLevel())
assert.EqualValues(t, "", opts.ApplicationName())
}

func TestSettingsOptions(t *testing.T) {
Expand All @@ -53,7 +54,8 @@ func TestSettingsOptions(t *testing.T) {
SetTLSConfig(tlsConfig).
SetHTTPRequestTimeout(50).
SetLogLevel(3).
AddDefaultTag("t", "a")
AddDefaultTag("t", "a").
SetApplicationName("Monitor/1.1")
assert.EqualValues(t, 5, opts.BatchSize())
assert.EqualValues(t, true, opts.UseGZip())
assert.EqualValues(t, 5_000, opts.FlushInterval())
Expand All @@ -66,6 +68,7 @@ func TestSettingsOptions(t *testing.T) {
assert.EqualValues(t, 5, opts.ExponentialBase())
assert.EqualValues(t, tlsConfig, opts.TLSConfig())
assert.EqualValues(t, 50, opts.HTTPRequestTimeout())
assert.EqualValues(t, "Monitor/1.1", opts.ApplicationName())
if client := opts.HTTPClient(); assert.NotNil(t, client) {
assert.EqualValues(t, 50*time.Second, client.Timeout)
assert.Equal(t, tlsConfig, client.Transport.(*http.Transport).TLSClientConfig)
Expand Down
2 changes: 1 addition & 1 deletion version.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ const (
)

func init() {
http.UserAgent = fmt.Sprintf("influxdb-client-go/%s (%s; %s)", Version, runtime.GOOS, runtime.GOARCH)
http.UserAgentBase = fmt.Sprintf("influxdb-client-go/%s (%s; %s)", Version, runtime.GOOS, runtime.GOARCH)
}

0 comments on commit 4a444de

Please sign in to comment.