Skip to content

Commit

Permalink
Update ServerRequest to accept server name (#3619)
Browse files Browse the repository at this point in the history
* Update ServerRequest to accept server name

* Update docs to include Apache and nginx examples

* Test the server not containing a port
  • Loading branch information
MrAlias authored Jan 26, 2023
1 parent 7e5d903 commit af3db6e
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 16 deletions.
19 changes: 17 additions & 2 deletions internal/tools/semconvkit/templates/httpconv/http.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,28 @@ func ClientStatus(code int) (codes.Code, string) {
}

// ServerRequest returns attributes for an HTTP request received by a server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
func ServerRequest(req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(req)
func ServerRequest(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(server, req)
}

// ServerStatus returns a span status code and message for an HTTP status code
Expand Down
29 changes: 27 additions & 2 deletions semconv/internal/v2/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,39 @@ func (c *HTTPConv) ClientRequest(req *http.Request) []attribute.KeyValue {
}

// ServerRequest returns attributes for an HTTP request received by a server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
func (c *HTTPConv) ServerRequest(req *http.Request) []attribute.KeyValue {
func (c *HTTPConv) ServerRequest(server string, req *http.Request) []attribute.KeyValue {
n := 5 // Method, scheme, target, proto, and host name.
host, p := splitHostPort(req.Host)
var host string
var p int
if server == "" {
host, p = splitHostPort(req.Host)
} else {
// Prioritize the primary server name.
host, p = splitHostPort(server)
if p < 0 {
_, p = splitHostPort(req.Host)
}
}
hostPort := requiredHTTPPort(req.TLS != nil, p)
if hostPort > 0 {
n++
Expand Down
25 changes: 23 additions & 2 deletions semconv/internal/v2/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,34 @@ func TestHTTPServerRequest(t *testing.T) {
attribute.String("enduser.id", user),
attribute.String("http.client_ip", clientIP),
},
hc.ServerRequest(req))
hc.ServerRequest("", req))
}

func TestHTTPServerName(t *testing.T) {
req := new(http.Request)
var got []attribute.KeyValue
const (
host = "test.semconv.server"
port = 8080
)
portStr := strconv.Itoa(port)
server := host + ":" + portStr
assert.NotPanics(t, func() { got = hc.ServerRequest(server, req) })
assert.Contains(t, got, attribute.String("net.host.name", host))
assert.Contains(t, got, attribute.Int("net.host.port", port))

req = &http.Request{Host: "alt.host.name:" + portStr}
// The server parameter does not include a port, ServerRequest should use
// the port in the request Host field.
assert.NotPanics(t, func() { got = hc.ServerRequest(host, req) })
assert.Contains(t, got, attribute.String("net.host.name", host))
assert.Contains(t, got, attribute.Int("net.host.port", port))
}

func TestHTTPServerRequestFailsGracefully(t *testing.T) {
req := new(http.Request)
var got []attribute.KeyValue
assert.NotPanics(t, func() { got = hc.ServerRequest(req) })
assert.NotPanics(t, func() { got = hc.ServerRequest("", req) })
want := []attribute.KeyValue{
attribute.String("http.method", "GET"),
attribute.String("http.target", ""),
Expand Down
19 changes: 17 additions & 2 deletions semconv/v1.13.0/httpconv/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,28 @@ func ClientStatus(code int) (codes.Code, string) {
}

// ServerRequest returns attributes for an HTTP request received by a server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
func ServerRequest(req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(req)
func ServerRequest(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(server, req)
}

// ServerStatus returns a span status code and message for an HTTP status code
Expand Down
19 changes: 17 additions & 2 deletions semconv/v1.14.0/httpconv/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,28 @@ func ClientStatus(code int) (codes.Code, string) {
}

// ServerRequest returns attributes for an HTTP request received by a server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
func ServerRequest(req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(req)
func ServerRequest(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(server, req)
}

// ServerStatus returns a span status code and message for an HTTP status code
Expand Down
19 changes: 17 additions & 2 deletions semconv/v1.15.0/httpconv/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,28 @@ func ClientStatus(code int) (codes.Code, string) {
}

// ServerRequest returns attributes for an HTTP request received by a server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
func ServerRequest(req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(req)
func ServerRequest(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(server, req)
}

// ServerStatus returns a span status code and message for an HTTP status code
Expand Down
19 changes: 17 additions & 2 deletions semconv/v1.16.0/httpconv/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,28 @@ func ClientStatus(code int) (codes.Code, string) {
}

// ServerRequest returns attributes for an HTTP request received by a server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
func ServerRequest(req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(req)
func ServerRequest(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(server, req)
}

// ServerStatus returns a span status code and message for an HTTP status code
Expand Down
19 changes: 17 additions & 2 deletions semconv/v1.17.0/httpconv/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,28 @@ func ClientStatus(code int) (codes.Code, string) {
}

// ServerRequest returns attributes for an HTTP request received by a server.
//
// The server must be the primary server name if it is known. For example this
// would be the ServerName directive
// (https://httpd.apache.org/docs/2.4/mod/core.html#servername) for an Apache
// server, and the server_name directive
// (http://nginx.org/en/docs/http/ngx_http_core_module.html#server_name) for an
// nginx server. More generically, the primary server name would be the host
// header value that matches the default virtual host of an HTTP server. It
// should include the host identifier and if a port is used to route to the
// server that port identifier should be included as an appropriate port
// suffix.
//
// If the primary server name is not known, server should be an empty string.
// The req Host will be used to determine the server instead.
//
// The following attributes are always returned: "http.method", "http.scheme",
// "http.flavor", "http.target", "net.host.name". The following attributes are
// returned if they related values are defined in req: "net.host.port",
// "net.sock.peer.addr", "net.sock.peer.port", "http.user_agent", "enduser.id",
// "http.client_ip".
func ServerRequest(req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(req)
func ServerRequest(server string, req *http.Request) []attribute.KeyValue {
return hc.ServerRequest(server, req)
}

// ServerStatus returns a span status code and message for an HTTP status code
Expand Down

0 comments on commit af3db6e

Please sign in to comment.