diff --git a/NOTICE.txt b/NOTICE.txt index 882dec0e07a..e394126e382 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -239,34 +239,6 @@ Contents of "NOTICE": See the License for the specific language governing permissions and Limitations under the License. --------------------------------------------------------------------- -Dependency: github.com/codahale/hdrhistogram -Revision: 3a0bb77429bd -License type (autodetected): MIT -Contents of "LICENSE": - - The MIT License (MIT) - - Copyright (c) 2014 Coda Hale - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - -------------------------------------------------------------------- Dependency: github.com/containerd/containerd Version: v1.3.3 @@ -575,6 +547,35 @@ Version: v8.0.0 Revision: aff00e5adfde License type (autodetected): Apache-2.0 +-------------------------------------------------------------------- +Dependency: github.com/elastic/go-hdrhistogram +Version: v0.1.0 +License type (autodetected): MIT +Contents of "LICENSE": + + The MIT License (MIT) + + Copyright (c) 2014 Coda Hale + Copyright (c) 2020 Elasticsearch BV + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + -------------------------------------------------------------------- Dependency: github.com/elastic/go-lumber Version: v0.1.0 diff --git a/changelogs/head.asciidoc b/changelogs/head.asciidoc index 691e45575c8..4faca77d3b3 100644 --- a/changelogs/head.asciidoc +++ b/changelogs/head.asciidoc @@ -9,6 +9,7 @@ https://github.com/elastic/apm-server/compare/7.7\...master[View commits] [float] ==== Bug fixes * Ensure applied flag can be set for agent configurations fetched for Jaeger {pull}3677[3677] +* Negative transaction and span durations now cause a schema validation error {pull}3721[3721] [float] ==== Intake API Changes diff --git a/docs/spec/spans/rum_v3_span.json b/docs/spec/spans/rum_v3_span.json index eb821074bb3..02a0202e537 100644 --- a/docs/spec/spans/rum_v3_span.json +++ b/docs/spec/spans/rum_v3_span.json @@ -188,7 +188,8 @@ }, "d": { "type": "number", - "description": "Duration of the span in milliseconds" + "description": "Duration of the span in milliseconds", + "minimum": 0 }, "n": { "type": "string", diff --git a/docs/spec/spans/span.json b/docs/spec/spans/span.json index 4270c067314..568ab4a05f4 100644 --- a/docs/spec/spans/span.json +++ b/docs/spec/spans/span.json @@ -195,7 +195,8 @@ }, "duration": { "type": "number", - "description": "Duration of the span in milliseconds" + "description": "Duration of the span in milliseconds", + "minimum": 0 }, "name": { "type": "string", diff --git a/docs/spec/transactions/rum_v3_transaction.json b/docs/spec/transactions/rum_v3_transaction.json index fb83385ae99..618ac11418c 100644 --- a/docs/spec/transactions/rum_v3_transaction.json +++ b/docs/spec/transactions/rum_v3_transaction.json @@ -64,7 +64,8 @@ }, "d": { "type": "number", - "description": "How long the transaction took to complete, in ms with 3 decimal points" + "description": "How long the transaction took to complete, in ms with 3 decimal points", + "minimum": 0 }, "rt": { "type": [ diff --git a/docs/spec/transactions/transaction.json b/docs/spec/transactions/transaction.json index 943e3d8852e..af7c2f50ba2 100644 --- a/docs/spec/transactions/transaction.json +++ b/docs/spec/transactions/transaction.json @@ -44,7 +44,8 @@ }, "duration": { "type": "number", - "description": "How long the transaction took to complete, in ms with 3 decimal points" + "description": "How long the transaction took to complete, in ms with 3 decimal points", + "minimum": 0 }, "result": { "type": ["string", "null"], diff --git a/model/modeldecoder/span_test.go b/model/modeldecoder/span_test.go index 2ea1c241f05..d15f090dfe7 100644 --- a/model/modeldecoder/span_test.go +++ b/model/modeldecoder/span_test.go @@ -269,21 +269,31 @@ func TestDecodeSpanInvalid(t *testing.T) { for name, test := range map[string]struct { input map[string]interface{} + err string }{ "transaction id wrong type": { input: map[string]interface{}{"transaction_id": 123}, + err: `type.*expected string or null, but got number`, }, "no trace_id": { input: map[string]interface{}{"trace_id": nil}, + err: `missing properties: "trace_id"`, }, "no id": { input: map[string]interface{}{"id": nil}, + err: `missing properties: "id"`, }, "no parent_id": { input: map[string]interface{}{"parent_id": nil}, + err: `missing properties: "parent_id"`, }, "invalid stacktrace": { input: map[string]interface{}{"stacktrace": []interface{}{"foo"}}, + err: `stacktrace.*expected object, but got string`, + }, + "negative duration": { + input: map[string]interface{}{"duration": -1.0}, + err: "duration.*must be >= 0 but found -1", }, } { t.Run(name, func(t *testing.T) { @@ -300,7 +310,7 @@ func TestDecodeSpanInvalid(t *testing.T) { } _, err := DecodeSpan(Input{Raw: input}) require.Error(t, err) - t.Logf("%s", err) + assert.Regexp(t, test.err, err.Error()) }) } } diff --git a/model/modeldecoder/transaction_test.go b/model/modeldecoder/transaction_test.go index 535682f25aa..f9d10e2365e 100644 --- a/model/modeldecoder/transaction_test.go +++ b/model/modeldecoder/transaction_test.go @@ -93,29 +93,49 @@ var fullTransactionInput = map[string]interface{}{ }, } -func TestTransactionEventDecodeFailure(t *testing.T) { +func TestDecodeTransactionInvalid(t *testing.T) { + _, err := DecodeTransaction(Input{Raw: nil}) + require.EqualError(t, err, "failed to validate transaction: error validating JSON: input missing") + + _, err = DecodeTransaction(Input{Raw: ""}) + require.EqualError(t, err, "failed to validate transaction: error validating JSON: invalid input type") + + baseInput := map[string]interface{}{ + "type": "type", + "trace_id": "trace_id", + "id": "id", + "duration": 123, + "span_count": map[string]interface{}{"dropped": 1.0, "started": 2.0}, + } + for name, test := range map[string]struct { - input interface{} + input map[string]interface{} err string - e *model.Transaction }{ - "no input": {input: nil, err: "failed to validate transaction: error validating JSON: input missing", e: nil}, - "invalid type": {input: "", err: "failed to validate transaction: error validating JSON: invalid input type", e: nil}, - "cannot fetch field": {input: map[string]interface{}{}, err: "failed to validate transaction: error validating JSON: (.|\n)*missing properties:(.|\n)*", e: nil}, + "missing trace_id": { + input: map[string]interface{}{"trace_id": nil}, + err: "missing properties: \"trace_id\"", + }, + "negative duration": { + input: map[string]interface{}{"duration": -1.0}, + err: "duration.*must be >= 0 but found -1", + }, } { t.Run(name, func(t *testing.T) { - transformable, err := DecodeTransaction(Input{Raw: test.input}) - if test.err != "" { - assert.Regexp(t, test.err, err.Error()) - } else { - assert.NoError(t, err) + input := make(map[string]interface{}) + for k, v := range baseInput { + input[k] = v } - if test.e != nil { - event := transformable.(*model.Transaction) - assert.Equal(t, test.e, event) - } else { - assert.Nil(t, transformable) + for k, v := range test.input { + if v == nil { + delete(input, k) + } else { + input[k] = v + } } + _, err := DecodeTransaction(Input{Raw: input}) + assert.Error(t, err) + assert.Regexp(t, test.err, err.Error()) }) } } diff --git a/model/span/generated/schema/rum_v3_span.go b/model/span/generated/schema/rum_v3_span.go index e307a7aa9f9..bc0eb407a8f 100644 --- a/model/span/generated/schema/rum_v3_span.go +++ b/model/span/generated/schema/rum_v3_span.go @@ -217,7 +217,8 @@ const RUMV3Schema = `{ }, "d": { "type": "number", - "description": "Duration of the span in milliseconds" + "description": "Duration of the span in milliseconds", + "minimum": 0 }, "n": { "type": "string", diff --git a/model/span/generated/schema/span.go b/model/span/generated/schema/span.go index e50ca0f4991..c70d368f976 100644 --- a/model/span/generated/schema/span.go +++ b/model/span/generated/schema/span.go @@ -323,7 +323,8 @@ const ModelSchema = `{ }, "duration": { "type": "number", - "description": "Duration of the span in milliseconds" + "description": "Duration of the span in milliseconds", + "minimum": 0 }, "name": { "type": "string", diff --git a/model/transaction/generated/schema/rum_v3_transaction.go b/model/transaction/generated/schema/rum_v3_transaction.go index 444fe186107..55becf6ec25 100644 --- a/model/transaction/generated/schema/rum_v3_transaction.go +++ b/model/transaction/generated/schema/rum_v3_transaction.go @@ -256,7 +256,8 @@ const RUMV3Schema = `{ }, "d": { "type": "number", - "description": "Duration of the span in milliseconds" + "description": "Duration of the span in milliseconds", + "minimum": 0 }, "n": { "type": "string", @@ -740,7 +741,8 @@ const RUMV3Schema = `{ }, "d": { "type": "number", - "description": "How long the transaction took to complete, in ms with 3 decimal points" + "description": "How long the transaction took to complete, in ms with 3 decimal points", + "minimum": 0 }, "rt": { "type": [ diff --git a/model/transaction/generated/schema/transaction.go b/model/transaction/generated/schema/transaction.go index 087330c1284..108ebcc32d8 100644 --- a/model/transaction/generated/schema/transaction.go +++ b/model/transaction/generated/schema/transaction.go @@ -451,7 +451,8 @@ const ModelSchema = `{ }, "duration": { "type": "number", - "description": "How long the transaction took to complete, in ms with 3 decimal points" + "description": "How long the transaction took to complete, in ms with 3 decimal points", + "minimum": 0 }, "result": { "type": ["string", "null"],