Skip to content

Commit

Permalink
[7.x] Index page URL and Referer as ECS fields (#3857) (#3865)
Browse files Browse the repository at this point in the history
* Index page URL and Referer as ECS fields (#3857)

* Update approval files (#3867)
  • Loading branch information
jalvz authored Jun 11, 2020
1 parent fd04dc1 commit e17593a
Show file tree
Hide file tree
Showing 40 changed files with 326 additions and 92 deletions.
5 changes: 5 additions & 0 deletions _meta/fields.common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@
description: >
The canonical headers of the monitored HTTP request.
- name: referrer
type: keyword
ignore_above: 1024
description: Referrer for this HTTP request.

- name: response
type: group
fields:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@
]
},
"method": "post",
"referrer": "http://localhost:8000/test/e2e/",
"socket": {
"encrypted": true,
"remote_address": "12.53.12.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@
]
},
"method": "post",
"referrer": "http://localhost:8000/test/e2e/",
"socket": {
"encrypted": true,
"remote_address": "12.53.12.1"
Expand Down
1 change: 1 addition & 0 deletions docs/data/elasticsearch/generated/errors.json
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@
]
},
"method": "post",
"referrer": "http://localhost:8000/test/e2e/",
"socket": {
"encrypted": true,
"remote_address": "8.8.8.8"
Expand Down
1 change: 1 addition & 0 deletions docs/data/elasticsearch/generated/transactions.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@
]
},
"method": "post",
"referrer": "http://localhost:8000/test/e2e/",
"socket": {
"encrypted": true,
"remote_address": "8.8.8.8"
Expand Down
9 changes: 9 additions & 0 deletions docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,15 @@ Object is not enabled.
--
*`http.request.referrer`*::
+
--
Referrer for this HTTP request.
type: keyword
--
*`http.response.status_code`*::
+
Expand Down
2 changes: 1 addition & 1 deletion include/fields.go

Large diffs are not rendered by default.

69 changes: 62 additions & 7 deletions model/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package model

import (
"net/http"
"net/url"
"strconv"

"github.com/elastic/beats/v7/libbeat/common"

Expand All @@ -28,7 +30,7 @@ import (
// Context holds all information sent under key context
type Context struct {
Http *Http
Url *Url
URL *URL
Labels *Labels
Page *Page
Custom *Custom
Expand All @@ -43,8 +45,8 @@ type Http struct {
Response *Resp
}

// Url describes request URL and its components
type Url struct {
// URL describes an URL and its components
type URL struct {
Original *string
Scheme *string
Full *string
Expand All @@ -55,9 +57,59 @@ type Url struct {
Fragment *string
}

// Page consists of Url string and referer
func ParseURL(original, hostname string) *URL {
original = truncate(original)
url, err := url.Parse(original)
if err != nil {
return &URL{Original: &original}
}
if url.Scheme == "" {
url.Scheme = "http"
}
if url.Host == "" {
url.Host = hostname
}
full := truncate(url.String())
out := &URL{
Original: &original,
Scheme: &url.Scheme,
Full: &full,
}
if path := truncate(url.Path); path != "" {
out.Path = &path
}
if query := truncate(url.RawQuery); query != "" {
out.Query = &query
}
if fragment := url.Fragment; fragment != "" {
out.Fragment = &fragment
}
if host := truncate(url.Hostname()); host != "" {
out.Domain = &host
}
if port := truncate(url.Port()); port != "" {
if intv, err := strconv.Atoi(port); err == nil {
out.Port = &intv
}
}
return out
}

// truncate returns s truncated at n runes, and the number of runes in the resulting string (<= n).
func truncate(s string) string {
var j int
for i := range s {
if j == 1024 {
return s[:i]
}
j++
}
return s
}

// Page consists of URL and referer
type Page struct {
Url *string
URL *URL
Referer *string
}

Expand Down Expand Up @@ -102,7 +154,7 @@ type MinimalResp struct {
}

// Fields returns common.MapStr holding transformed data for attribute url.
func (url *Url) Fields() common.MapStr {
func (url *URL) Fields() common.MapStr {
if url == nil {
return nil
}
Expand Down Expand Up @@ -146,7 +198,10 @@ func (page *Page) Fields() common.MapStr {
return nil
}
var fields = common.MapStr{}
utility.Set(fields, "url", page.Url)
// Remove in 8.0
if page.URL != nil {
utility.Set(fields, "url", page.URL.Original)
}
utility.Set(fields, "referer", page.Referer)
return fields
}
Expand Down
13 changes: 11 additions & 2 deletions model/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ type Error struct {
Labels *Labels
Page *Page
HTTP *Http
URL *Url
URL *URL
Custom *Custom

Exception *Exception
Expand Down Expand Up @@ -117,7 +117,16 @@ func (e *Error) Transform(ctx context.Context, tctx *transform.Context) []beat.E
// merges with metadata labels, overrides conflicting keys
utility.DeepUpdate(fields, "labels", e.Labels.Fields())
utility.Set(fields, "http", e.HTTP.Fields())
utility.Set(fields, "url", e.URL.Fields())
urlFields := e.URL.Fields()
if urlFields != nil {
utility.Set(fields, "url", e.URL.Fields())
}
if e.Page != nil {
utility.DeepUpdate(fields, "http.request.referrer", e.Page.Referer)
if urlFields == nil {
utility.Set(fields, "url", e.Page.URL.Fields())
}
}
utility.Set(fields, "experimental", e.Experimental)

// sampled and type is nil if an error happens outside a transaction or an (old) agent is not sending sampled info
Expand Down
64 changes: 63 additions & 1 deletion model/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ func TestEvents(t *testing.T) {
TransactionID: trID,
TransactionSampled: &sampledTrue,
Labels: &labels,
Page: &Page{Url: &url, Referer: &referer},
Page: &Page{URL: &URL{Original: &url}, Referer: &referer},
Custom: &custom,
},

Expand Down Expand Up @@ -388,6 +388,12 @@ func TestEvents(t *testing.T) {
}},
"page": common.MapStr{"url": url, "referer": referer},
},
"http": common.MapStr{
"request": common.MapStr{
"referrer": referer,
},
},
"url": common.MapStr{"original": url},
"processor": common.MapStr{"event": "error", "name": "error"},
"transaction": common.MapStr{"id": "945254c5-67a5-417e-8a4e-aa29efcbfb79", "sampled": true},
"timestamp": common.MapStr{"us": timestampUs},
Expand Down Expand Up @@ -532,6 +538,62 @@ func TestCulprit(t *testing.T) {
}
}

func TestErrorTransformPage(t *testing.T) {
id := "123"
urlExample := "http://example.com/path"

tests := []struct {
Error Error
Output common.MapStr
Msg string
}{
{
Error: Error{
ID: &id,
Page: &Page{
URL: ParseURL(urlExample, ""),
Referer: nil,
},
},
Output: common.MapStr{
"domain": "example.com",
"full": "http://example.com/path",
"original": "http://example.com/path",
"path": "/path",
"scheme": "http",
},
Msg: "With page URL",
},
{
Error: Error{
ID: &id,
Timestamp: time.Now(),
URL: ParseURL("https://localhost:8200/", ""),
Page: &Page{
URL: ParseURL(urlExample, ""),
Referer: nil,
},
},
Output: common.MapStr{
"domain": "localhost",
"full": "https://localhost:8200/",
"original": "https://localhost:8200/",
"path": "/",
"port": 8200,
"scheme": "https",
},
Msg: "With Page URL and Request URL",
},
}

tctx := &transform.Context{}

for idx, test := range tests {
output := test.Error.Transform(context.Background(), tctx)
assert.Equal(t, test.Output, output[0].Fields["url"], fmt.Sprintf("Failed at idx %v; %s", idx, test.Msg))
}
}

func TestEmptyGroupingKey(t *testing.T) {
emptyGroupingKey := hex.EncodeToString(md5.New().Sum(nil))
e := Error{}
Expand Down
15 changes: 9 additions & 6 deletions model/modeldecoder/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func decodeContext(input map[string]interface{}, cfg Config, meta *model.Metadat

ctx := model.Context{
Http: http,
Url: url,
URL: url,
Page: page,
Custom: custom,
Message: message,
Expand Down Expand Up @@ -87,7 +87,7 @@ func decodeContext(input map[string]interface{}, cfg Config, meta *model.Metadat
return &ctx, nil
}

func decodeURL(raw common.MapStr, err error) (*model.Url, error) {
func decodeURL(raw common.MapStr, err error) (*model.URL, error) {
if err != nil {
return nil, err
}
Expand All @@ -99,7 +99,7 @@ func decodeURL(raw common.MapStr, err error) (*model.Url, error) {
}

inpURL := decoder.MapStr(req, "url")
url := model.Url{
url := model.URL{
Original: decoder.StringPtr(inpURL, "raw"),
Full: decoder.StringPtr(inpURL, "full"),
Domain: decoder.StringPtr(inpURL, "hostname"),
Expand Down Expand Up @@ -217,10 +217,13 @@ func decodePage(raw common.MapStr, hasShortFieldNames bool, err error) (*model.P
return nil, nil
}
decoder := utility.ManualDecoder{}
return &model.Page{
Url: decoder.StringPtr(pageInput, fieldName("url")),
page := &model.Page{
Referer: decoder.StringPtr(pageInput, fieldName("referer")),
}, decoder.Err
}
if pageURL := decoder.StringPtr(pageInput, fieldName("url")); pageURL != nil {
page.URL = model.ParseURL(*pageURL, "")
}
return page, decoder.Err
}

func decodeCustom(raw common.MapStr, hasShortFieldNames bool, err error) (*model.Custom, error) {
Expand Down
2 changes: 1 addition & 1 deletion model/modeldecoder/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func decodeError(input Input, schema *jsonschema.Schema) (*m.Error, error) {
Labels: ctx.Labels,
Page: ctx.Page,
HTTP: ctx.Http,
URL: ctx.Url,
URL: ctx.URL,
Custom: ctx.Custom,
Experimental: ctx.Experimental,
Timestamp: decoder.TimeEpochMicro(raw, "timestamp"),
Expand Down
4 changes: 2 additions & 2 deletions model/modeldecoder/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ func TestErrorEventDecode(t *testing.T) {
transactionType := "request"
labels := m.Labels{"ab": "c"}
ua := "go-1.1"
page := m.Page{Url: &pURL, Referer: &referer}
page := m.Page{URL: m.ParseURL(pURL, ""), Referer: &referer}
custom := m.Custom{"a": "b"}
request := m.Req{Method: "post", Socket: &m.Socket{}, Headers: http.Header{"User-Agent": []string{ua}}, Cookies: map[string]interface{}{"a": "b"}}
response := m.Resp{Finished: new(bool), MinimalResp: m.MinimalResp{Headers: http.Header{"Content-Type": []string{"text/html"}}}}
h := m.Http{Request: &request, Response: &response}
ctxURL := m.Url{Original: &origURL}
ctxURL := m.URL{Original: &origURL}
inputMetadata := m.Metadata{
Service: m.Service{Name: "foo"},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"Labels": null,
"Message": null,
"Page": null,
"Url": {
"URL": {
"Domain": null,
"Fragment": null,
"Full": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"Labels": null,
"Message": null,
"Page": null,
"Url": {
"URL": {
"Domain": null,
"Fragment": null,
"Full": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"Labels": null,
"Message": null,
"Page": null,
"Url": {
"URL": {
"Domain": null,
"Fragment": null,
"Full": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"Labels": null,
"Message": null,
"Page": null,
"Url": {
"URL": {
"Domain": null,
"Fragment": null,
"Full": null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"Labels": null,
"Message": null,
"Page": null,
"Url": null
"URL": null
}
Loading

0 comments on commit e17593a

Please sign in to comment.