Skip to content

Commit

Permalink
send metadata during handshake (#28)
Browse files Browse the repository at this point in the history
fix [#484](https://github.com/go-mgo/mgo/issues/484)

Annotate connections with metadata provided by the
connecting client.

informations send:

{
 "aplication": {         // optional
   "name": "myAppName"
 }
 "driver": {
    "name": "mgo",
    "version": "v2"
  },
  "os": {
    "type": runtime.GOOS,
    "architecture": runtime.GOARCH
  }
}

to set "application.name", add `appname` param in options
of string connection URI,
for example : "mongodb://localhost:27017?appname=myAppName"
  • Loading branch information
feliixx authored and domodwyer committed Sep 6, 2017
1 parent 93aaa6e commit 165af68
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
17 changes: 15 additions & 2 deletions cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"errors"
"fmt"
"net"
"runtime"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -61,16 +62,18 @@ type mongoCluster struct {
cachedIndex map[string]bool
sync chan bool
dial dialer
appName string
}

func newCluster(userSeeds []string, direct, failFast bool, dial dialer, setName string) *mongoCluster {
func newCluster(userSeeds []string, direct, failFast bool, dial dialer, setName string, appName string) *mongoCluster {
cluster := &mongoCluster{
userSeeds: userSeeds,
references: 1,
direct: direct,
failFast: failFast,
dial: dial,
setName: setName,
appName: appName,
}
cluster.serverSynced.L = cluster.RWMutex.RLocker()
cluster.sync = make(chan bool, 1)
Expand Down Expand Up @@ -144,7 +147,17 @@ func (cluster *mongoCluster) isMaster(socket *mongoSocket, result *isMasterResul
// Monotonic let's it talk to a slave and still hold the socket.
session := newSession(Monotonic, cluster, 10*time.Second)
session.setSocket(socket)
err := session.Run("ismaster", result)

// provide some meta infos on the client,
// see https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst#connection-handshake
// for details
metaInfo := bson.M{"driver": bson.M{"name": "mgo", "version": "globalsign"},
"os": bson.M{"type": runtime.GOOS, "architecture": runtime.GOARCH}}

if cluster.appName != "" {
metaInfo["application"] = bson.M{"name": cluster.appName}
}
err := session.Run(bson.D{{"isMaster", 1}, {"client", metaInfo}}, result)
session.Close()
return err
}
Expand Down
16 changes: 15 additions & 1 deletion session.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ const (
// Defines the per-server socket pool limit. Defaults to 4096.
// See Session.SetPoolLimit for details.
//
// appName=<appName>
//
// The identifier of the client application which ran the operation. This
// param can't exceed 128 bytes
//
// Relevant documentation:
//
Expand Down Expand Up @@ -279,6 +283,7 @@ func ParseURL(url string) (*DialInfo, error) {
source := ""
setName := ""
poolLimit := 0
appName := ""
readPreferenceMode := Primary
var readPreferenceTagSets []bson.D
for _, opt := range uinfo.options {
Expand All @@ -296,6 +301,11 @@ func ParseURL(url string) (*DialInfo, error) {
if err != nil {
return nil, errors.New("bad value for maxPoolSize: " + opt.value)
}
case "appName":
if len(opt.value) > 128 {
return nil, errors.New("appName too long, must be < 128 bytes: " + opt.value)
}
appName = opt.value
case "readPreference":
switch opt.value {
case "nearest":
Expand Down Expand Up @@ -350,6 +360,7 @@ func ParseURL(url string) (*DialInfo, error) {
Service: service,
Source: source,
PoolLimit: poolLimit,
AppName: appName,
ReadPreference: &ReadPreference{
Mode: readPreferenceMode,
TagSets: readPreferenceTagSets,
Expand Down Expand Up @@ -409,6 +420,9 @@ type DialInfo struct {
// See Session.SetPoolLimit for details.
PoolLimit int

// The identifier of the client application which ran the operation.
AppName string

// ReadPreference defines the manner in which servers are chosen. See
// Session.SetMode and Session.SelectServers.
ReadPreference *ReadPreference
Expand Down Expand Up @@ -472,7 +486,7 @@ func DialWithInfo(info *DialInfo) (*Session, error) {
}
addrs[i] = addr
}
cluster := newCluster(addrs, info.Direct, info.FailFast, dialer{info.Dial, info.DialServer}, info.ReplicaSetName)
cluster := newCluster(addrs, info.Direct, info.FailFast, dialer{info.Dial, info.DialServer}, info.ReplicaSetName, info.AppName)
session := newSession(Eventual, cluster, info.Timeout)
session.defaultdb = info.Database
if session.defaultdb == "" {
Expand Down
44 changes: 44 additions & 0 deletions session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,50 @@ func (s *S) TestURLInvalidReadPreferenceTags(c *C) {
}
}

func (s *S) TestURLWithAppName(c *C) {
if !s.versionAtLeast(3, 4) {
c.Skip("appName depends on MongoDB 3.4+")
}
appName := "myAppName"
session, err := mgo.Dial("localhost:40001?appName=" + appName)
c.Assert(err, IsNil)
defer session.Close()

db := session.DB("mydb")

err = db.Run(bson.D{{"profile", 2}}, nil)
c.Assert(err, IsNil)

coll := db.C("mycoll")
err = coll.Insert(M{"a": 1, "b": 2})
c.Assert(err, IsNil)

result := struct{ A, B int }{}
err = coll.Find(M{"a": 1}).One(&result)
c.Assert(err, IsNil)

profileResult := struct {
AppName string `bson:"appName"`
}{}

err = db.C("system.profile").Find(nil).Sort("-ts").One(&profileResult)
c.Assert(err, IsNil)
c.Assert(appName, Equals, profileResult.AppName)
// reset profiling to 0 as it add unecessary overhead to all other test
err = db.Run(bson.D{{"profile", 0}}, nil)
c.Assert(err, IsNil)
}

func (s *S) TestURLWithAppNameTooLong(c *C) {
if !s.versionAtLeast(3, 4) {
c.Skip("appName depends on MongoDB 3.4+")
}
appName := "myAppNameWayTooLongmyAppNameWayTooLongmyAppNameWayTooLongmyAppNameWayTooLong"
appName += appName
_, err := mgo.Dial("localhost:40001?appName=" + appName)
c.Assert(err, ErrorMatches, "appName too long, must be < 128 bytes: "+appName)
}

func (s *S) TestInsertFindOne(c *C) {
session, err := mgo.Dial("localhost:40001")
c.Assert(err, IsNil)
Expand Down

0 comments on commit 165af68

Please sign in to comment.