diff --git a/Makefile b/Makefile index 0ffeda5e6e0..779191c3034 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,6 @@ update: fields go-generate add-headers copy-docs notice $(MAGE) @$(MAGE) update fields_sources=\ - _meta/fields.common.yml \ $(shell find model -name fields.yml) \ $(shell find x-pack/apm-server/fields -name fields.yml) diff --git a/NOTICE.txt b/NOTICE.txt index 3c2bc199726..ab8fa83e7ea 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -3498,11 +3498,6 @@ Contents of "LICENSE": (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------- -Dependency: github.com/ua-parser/uap-go -Revision: e1c09f13e2fe -License type (autodetected): Apache-2.0 - -------------------------------------------------------------------- Dependency: github.com/uber/tchannel-go Version: v1.16.0 diff --git a/_meta/fields.common.yml b/_meta/fields.common.yml deleted file mode 100644 index d4d24ad0317..00000000000 --- a/_meta/fields.common.yml +++ /dev/null @@ -1,808 +0,0 @@ -- key: apm - title: General APM - description: > - Fields common to various APM events. - fields: - - name: data_stream.type - type: keyword - description: "Data stream type: logs, metrics, or traces." - example: traces - - - name: data_stream.dataset - type: keyword - description: Data stream dataset name. - example: backend_service - - - name: data_stream.namespace - type: keyword - description: User-defined data stream namespace. - example: production - - - name: processor.name - type: keyword - description: Processor name. - - - name: processor.event - type: keyword - description: Processor event. - - - name: timestamp - type: group - fields: - - name: us - type: long - count: 1 - description: > - Timestamp of the event in microseconds since Unix epoch. - - - name: url - type: group - description: > - A complete Url, with scheme, host and path. - dynamic: false - fields: - - - name: scheme - type: keyword - description: > - The protocol of the request, e.g. "https:". - overwrite: true - - - name: full - type: keyword - description: > - The full, possibly agent-assembled URL of the request, e.g https://example.com:443/search?q=elasticsearch#top. - overwrite: true - - - name: domain - type: keyword - description: > - The hostname of the request, e.g. "example.com". - overwrite: true - - - name: port - type: long - description: > - The port of the request, e.g. 443. - overwrite: true - - - name: path - type: keyword - description: > - The path of the request, e.g. "/search". - overwrite: true - - - name: query - type: keyword - description: > - The query string of the request, e.g. "q=elasticsearch". - overwrite: true - - - name: fragment - type: keyword - description: > - A fragment specifying a location in a web page , e.g. "top". - overwrite: true - - - name: http - type: group - dynamic: false - fields: - - - name: version - type: keyword - description: > - The http version of the request leading to this event. - overwrite: true - - - name: request - type: group - fields: - - - name: method - type: keyword - description: > - The http method of the request leading to this event. - overwrite: true - - - name: headers - type: object - enabled: false - description: > - The canonical headers of the monitored HTTP request. - - - name: referrer - type: keyword - ignore_above: 1024 - overwrite: true - description: Referrer for this HTTP request. - - - name: response - type: group - fields: - - - name: status_code - type: long - description: > - The status code of the HTTP response. - overwrite: true - - - name: finished - type: boolean - description: > - Used by the Node agent to indicate when in the response life cycle an error has occurred. - overwrite: true - - - name: headers - type: object - enabled: false - description: > - The canonical headers of the monitored HTTP response. - - - name: labels - type: object - object_type_params: - - object_type: keyword - - object_type: boolean - - object_type: scaled_float - scaling_factor: 1000000 - dynamic: true - overwrite: true - description: > - A flat mapping of user-defined labels with string, boolean or number values. - - - name: service - type: group - dynamic: false - description: > - Service fields. - fields: - - name: name - type: keyword - description: > - Immutable name of the service emitting this event. - overwrite: true - - - name: version - type: keyword - description: > - Version of the service emitting this event. - overwrite: true - - - name: environment - type: keyword - description: > - Service environment. - - - name: node - type: group - fields: - - name: name - type: keyword - description: > - Unique meaningful name of the service node. - overwrite: true - - - name: language - type: group - fields: - - - name: name - type: keyword - description: > - Name of the programming language used. - - - name: version - type: keyword - description: > - Version of the programming language used. - - - name: runtime - type: group - fields: - - - name: name - type: keyword - description: > - Name of the runtime used. - - - name: version - type: keyword - description: > - Version of the runtime used. - - - name: framework - type: group - fields: - - - name: name - type: keyword - description: > - Name of the framework used. - - - name: version - type: keyword - description: > - Version of the framework used. - - - name: transaction - type: group - dynamic: false - fields: - - name: id - type: keyword - description: > - The transaction ID. - - name: sampled - type: boolean - description: > - Transactions that are 'sampled' will include all available information. Transactions that are not sampled will not have spans or context. - - name: type - type: keyword - description: > - Keyword of specific relevance in the service's domain (eg. 'request', 'backgroundjob', etc) - - name: name - type: keyword - multi_fields: - - name: text - type: text - description: > - Generic designation of a transaction in the scope of a single service (eg. 'GET /users/:id'). - - - name: duration - type: group - fields: - - name: count - type: long - - name: sum - type: group - fields: - - name: us - type: long - - - name: self_time - type: group - description: > - Portion of the transaction's duration where no direct child was running - fields: - - name: count - type: long - - name: sum - type: group - fields: - - name: us - type: long - - - name: breakdown - type: group - description: > - Counter for collected breakdowns for the transaction - fields: - - name: count - type: long - - - name: span - type: group - dynamic: false - fields: - - name: type - type: keyword - count: 1 - description: > - Keyword of specific relevance in the service's domain (eg: 'db.postgresql.query', 'template.erb', 'cache', etc). - - - name: subtype - type: keyword - count: 1 - description: > - A further sub-division of the type (e.g. postgresql, elasticsearch) - - - name: self_time - type: group - description: > - Portion of the span's duration where no direct child was running - fields: - - name: count - type: long - - name: sum - type: group - fields: - - name: us - type: long - - - name: trace - type: group - dynamic: false - fields: - - name: id - type: keyword - description: > - The ID of the trace to which the event belongs to. - - - name: parent - type: group - dynamic: false - fields: - - name: id - type: keyword - description: > - The ID of the parent event. - - - name: agent - type: group - dynamic: false - fields: - - - name: name - type: keyword - description: > - Name of the agent used. - overwrite: true - - - name: version - type: keyword - description: > - Version of the agent used. - overwrite: true - - - name: ephemeral_id - type: keyword - description: > - The Ephemeral ID identifies a running process. - overwrite: true - - - name: container - type: group - dynamic: false - title: Container - description: > - Container fields are used for meta information about the specific container - that is the source of information. These fields help correlate data based - containers from any runtime. - fields: - - - name: id - type: keyword - description: > - Unique container id. - overwrite: true - - - name: kubernetes - type: group - dynamic: false - title: Kubernetes - description: > - Kubernetes metadata reported by agents - fields: - - - name: namespace - type: keyword - description: > - Kubernetes namespace - overwrite: true - - - name: node - type: group - fields: - - name: name - type: keyword - description: > - Kubernetes node name - overwrite: true - - - name: pod - type: group - fields: - - - name: name - type: keyword - description: > - Kubernetes pod name - overwrite: true - - - name: uid - type: keyword - description: > - Kubernetes Pod UID - overwrite: true - - - name: host - type: group - dynamic: false - description: > - Optional host fields. - fields: - - - name: architecture - type: keyword - description: > - The architecture of the host the event was recorded on. - overwrite: true - - - name: hostname - type: keyword - description: > - The hostname of the host the event was recorded on. - overwrite: true - - - name: name - type: keyword - description: > - Name of the host the event was recorded on. - It can contain same information as host.hostname or a name specified by the user. - overwrite: true - - - name: ip - type: ip - description: > - IP of the host that records the event. - overwrite: true - - - name: os - title: Operating System - group: 2 - description: > - The OS fields contain information about the operating system. - type: group - fields: - - name: platform - type: keyword - description: > - The platform of the host the event was recorded on. - overwrite: true - - - name: process - type: group - dynamic: false - description: > - Information pertaining to the running process where the data was collected - fields: - - name: args - level: extended - type: keyword - description: > - Process arguments. - - May be filtered to protect sensitive information. - overwrite: true - - - name: pid - type: long - description: > - Numeric process ID of the service process. - overwrite: true - - - name: ppid - type: long - description: > - Numeric ID of the service's parent process. - overwrite: true - - - name: title - type: keyword - description: > - Service process title. - overwrite: true - - - name: observer - type: group - dynamic: false - fields: - - - name: listening - type: keyword - description: > - Address the server is listening on. - - - name: hostname - type: keyword - overwrite: true - description: > - Hostname of the APM Server. - - - name: version - type: keyword - overwrite: true - description: > - APM Server version. - - - name: version_major - type: byte - description: > - Major version number of the observer - - - name: type - type: keyword - overwrite: true - description: > - The type will be set to `apm-server`. - - - name: user - type: group - dynamic: false - fields: - - - name: name - type: keyword - description: > - The username of the logged in user. - overwrite: true - - - name: id - type: keyword - description: > - Identifier of the logged in user. - overwrite: true - - - name: email - type: keyword - description: > - Email of the logged in user. - overwrite: true - - - name: client - dynamic: false - type: group - fields: - - name: ip - type: ip - description: > - IP address of the client of a recorded event. - This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. - overwrite: true - - - name: source - dynamic: false - type: group - fields: - - name: ip - type: ip - description: > - IP address of the source of a recorded event. - This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. - overwrite: true - - - name: destination - title: Destination - group: 2 - description: 'Destination fields describe details about the destination of a packet/event. - - Destination fields are usually populated in conjunction with source fields.' - type: group - fields: - - name: address - level: extended - type: keyword - ignore_above: 1024 - description: 'Some event destination addresses are defined ambiguously. The - event will sometimes list an IP, a domain or a unix socket. You should always - store the raw address in the `.address` field. - - Then it should be duplicated to `.ip` or `.domain`, depending on which one - it is.' - overwrite: true - - - name: ip - level: core - type: ip - description: 'IP addess of the destination. - - Can be one of multiple IPv4 or IPv6 addresses.' - overwrite: true - - - name: port - level: core - type: long - format: string - description: Port of the destination. - overwrite: true - - - name: user_agent - dynamic: false - title: User agent - description: > - The user_agent fields normally come from a browser request. They often - show up in web service logs coming from the parsed user agent string. - type: group - overwrite: true - fields: - - - name: original - type: keyword - description: > - Unparsed version of the user_agent. - example: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1" - overwrite: true - - multi_fields: - - name: text - type: text - description: > - Software agent acting in behalf of a user, eg. a web browser / OS combination. - overwrite: true - - - name: name - type: keyword - overwrite: true - example: Safari - description: > - Name of the user agent. - - - name: version - type: keyword - overwrite: true - description: > - Version of the user agent. - example: 12.0 - - - name: device - type: group - overwrite: true - title: Device - description: > - Information concerning the device. - fields: - - - name: name - type: keyword - overwrite: true - example: iPhone - description: > - Name of the device. - - - name: os - type: group - overwrite: true - title: Operating System - description: > - The OS fields contain information about the operating system. - fields: - - - name: platform - type: keyword - overwrite: true - description: > - Operating system platform (such centos, ubuntu, windows). - example: darwin - - - name: name - type: keyword - overwrite: true - example: "Mac OS X" - description: > - Operating system name, without the version. - - - name: full - type: keyword - overwrite: true - example: "Mac OS Mojave" - description: > - Operating system name, including the version or code name. - - - name: family - type: keyword - overwrite: true - example: "debian" - description: > - OS family (such as redhat, debian, freebsd, windows). - - - name: version - type: keyword - overwrite: true - example: "10.14.1" - description: > - Operating system version as a raw string. - - - name: kernel - type: keyword - overwrite: true - example: "4.4.0-112-generic" - description: > - Operating system kernel version as a raw string. - - - name: experimental - type: object - dynamic: true - description: Additional experimental data sent by the agents. - - - name: cloud - title: Cloud - group: 2 - type: group - description: > - Cloud metadata reported by agents - fields: - - name: account - type: group - dynamic: false - fields: - - name: id - level: extended - type: keyword - ignore_above: 1024 - description: Cloud account ID - overwrite: true - - name: name - level: extended - type: keyword - ignore_above: 1024 - description: Cloud account name - overwrite: true - - name: availability_zone - level: extended - type: keyword - ignore_above: 1024 - description: Cloud availability zone name - example: us-east1-a - overwrite: true - - name: instance - type: group - dynamic: false - fields: - - name: id - level: extended - type: keyword - ignore_above: 1024 - description: Cloud instance/machine ID - overwrite: true - - name: name - level: extended - type: keyword - ignore_above: 1024 - description: Cloud instance/machine name - overwrite: true - - name: machine - type: group - dynamic: false - fields: - - name: type - level: extended - type: keyword - ignore_above: 1024 - description: Cloud instance/machine type - example: t2.medium - overwrite: true - - name: project - type: group - dynamic: false - fields: - - name: id - level: extended - type: keyword - ignore_above: 1024 - description: Cloud project ID - overwrite: true - - name: name - level: extended - type: keyword - ignore_above: 1024 - description: Cloud project name - overwrite: true - - name: provider - level: extended - type: keyword - ignore_above: 1024 - description: Cloud provider name - example: gcp - overwrite: true - - name: region - level: extended - type: keyword - ignore_above: 1024 - description: Cloud region name - example: us-east1 - overwrite: true - - - name: event - type: group - fields: - - - name: outcome - level: core - type: keyword - ignore_above: 1024 - description: > - `event.outcome` simply denotes whether the event represents a success or a - failure from the perspective of the entity that produced the event. - example: success - overwrite: true diff --git a/beater/config/aggregation.go b/beater/config/aggregation.go index d674dedabd6..dcbaa0e763a 100644 --- a/beater/config/aggregation.go +++ b/beater/config/aggregation.go @@ -25,7 +25,6 @@ const ( defaultTransactionAggregationInterval = time.Minute defaultTransactionAggregationMaxGroups = 10000 defaultTransactionAggregationHDRHistogramSignificantFigures = 2 - defaultTransactionAggregationRUMUserAgentLRUSize = 5000 defaultServiceDestinationAggregationInterval = time.Minute defaultServiceDestinationAggregationMaxGroups = 10000 @@ -43,7 +42,6 @@ type TransactionAggregationConfig struct { Interval time.Duration `config:"interval" validate:"min=1"` MaxTransactionGroups int `config:"max_groups" validate:"min=1"` HDRHistogramSignificantFigures int `config:"hdrhistogram_significant_figures" validate:"min=1, max=5"` - RUMUserAgentLRUSize int `config:"rum.user_agent.lru_size" validate:"min=1"` } // ServiceDestinationAggregationConfig holds configuration related to span metrics aggregation for service maps. @@ -59,7 +57,6 @@ func defaultAggregationConfig() AggregationConfig { Interval: defaultTransactionAggregationInterval, MaxTransactionGroups: defaultTransactionAggregationMaxGroups, HDRHistogramSignificantFigures: defaultTransactionAggregationHDRHistogramSignificantFigures, - RUMUserAgentLRUSize: defaultTransactionAggregationRUMUserAgentLRUSize, }, ServiceDestinations: ServiceDestinationAggregationConfig{ Enabled: true, diff --git a/beater/config/config_test.go b/beater/config/config_test.go index 925d5d4f2c5..d8852b89371 100644 --- a/beater/config/config_test.go +++ b/beater/config/config_test.go @@ -122,11 +122,6 @@ func TestUnpackConfig(t *testing.T) { "interval": "1s", "max_groups": 123, "hdrhistogram_significant_figures": 1, - "rum": map[string]interface{}{ - "user_agent": map[string]interface{}{ - "lru_size": 123, - }, - }, }, "service_destinations": map[string]interface{}{ "max_groups": 456, @@ -222,7 +217,6 @@ func TestUnpackConfig(t *testing.T) { Interval: time.Second, MaxTransactionGroups: 123, HDRHistogramSignificantFigures: 1, - RUMUserAgentLRUSize: 123, }, ServiceDestinations: ServiceDestinationAggregationConfig{ Enabled: true, @@ -273,12 +267,11 @@ func TestUnpackConfig(t *testing.T) { }, }, }, - "jaeger.grpc.enabled": true, - "api_key.enabled": true, - "aggregation.transactions.enabled": true, - "aggregation.transactions.rum.user_agent.lru_size": 123, - "aggregation.service_destinations.enabled": false, - "sampling.keep_unsampled": false, + "jaeger.grpc.enabled": true, + "api_key.enabled": true, + "aggregation.transactions.enabled": true, + "aggregation.service_destinations.enabled": false, + "sampling.keep_unsampled": false, "sampling.tail": map[string]interface{}{ "enabled": true, "interval": "2m", @@ -358,7 +351,6 @@ func TestUnpackConfig(t *testing.T) { Interval: time.Minute, MaxTransactionGroups: 10000, HDRHistogramSignificantFigures: 2, - RUMUserAgentLRUSize: 123, }, ServiceDestinations: ServiceDestinationAggregationConfig{ Enabled: false, @@ -456,24 +448,24 @@ func TestTLSSettings(t *testing.T) { "ConfiguredToRequired": { config: map[string]interface{}{"ssl": map[string]interface{}{ "client_authentication": "required", - "key": "../../testdata/tls/key.pem", - "certificate": "../../testdata/tls/certificate.pem", + "key": "../../testdata/tls/key.pem", + "certificate": "../../testdata/tls/certificate.pem", }}, tls: &tlscommon.ServerConfig{ClientAuth: 4, Certificate: testdataCertificateConfig}, }, "ConfiguredToOptional": { config: map[string]interface{}{"ssl": map[string]interface{}{ "client_authentication": "optional", - "key": "../../testdata/tls/key.pem", - "certificate": "../../testdata/tls/certificate.pem", + "key": "../../testdata/tls/key.pem", + "certificate": "../../testdata/tls/certificate.pem", }}, tls: &tlscommon.ServerConfig{ClientAuth: 3, Certificate: testdataCertificateConfig}, }, "DefaultRequiredByCA": { config: map[string]interface{}{"ssl": map[string]interface{}{ "certificate_authorities": []string{"../../testdata/tls/ca.crt.pem"}, - "key": "../../testdata/tls/key.pem", - "certificate": "../../testdata/tls/certificate.pem", + "key": "../../testdata/tls/key.pem", + "certificate": "../../testdata/tls/certificate.pem", }}, tls: &tlscommon.ServerConfig{ClientAuth: 4, Certificate: testdataCertificateConfig}, }, @@ -481,8 +473,8 @@ func TestTLSSettings(t *testing.T) { config: map[string]interface{}{"ssl": map[string]interface{}{ "client_authentication": "none", "certificate_authorities": []string{"../../testdata/tls/ca.crt.pem"}, - "key": "../../testdata/tls/key.pem", - "certificate": "../../testdata/tls/certificate.pem", + "key": "../../testdata/tls/key.pem", + "certificate": "../../testdata/tls/certificate.pem", }}, tls: &tlscommon.ServerConfig{ClientAuth: 0, Certificate: testdataCertificateConfig}, }, diff --git a/cmd/root.go b/cmd/root.go index eda0dcd68f4..57aa3502a6a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -48,31 +48,9 @@ var libbeatConfigOverrides = []cfgfile.ConditionalOverride{{ "metrics": map[string]interface{}{ "enabled": false, }, - "files": map[string]interface{}{ - "rotateeverybytes": 10 * 1024 * 1024, - }, - }, - "setup": map[string]interface{}{ - "template": map[string]interface{}{ - "settings": map[string]interface{}{ - "index": map[string]interface{}{ - "codec": "best_compression", - "mapping": map[string]interface{}{ - "total_fields": map[string]int{ - "limit": 2000, - }, - }, - "number_of_shards": 1, - }, - "_source": map[string]interface{}{ - "enabled": true, - }, - }, - }, }, }), -}, -} +}} // DefaultSettings return the default settings for APM Server to pass into // the GenRootCmdWithSettings. diff --git a/docs/fields.asciidoc b/docs/fields.asciidoc index a675e611972..24bb81f1d7a 100644 --- a/docs/fields.asciidoc +++ b/docs/fields.asciidoc @@ -12,7 +12,6 @@ This file is generated! See _meta/fields.yml and scripts/generate_fields_docs.py This document describes the fields that are exported by Apm-Server. They are grouped in the following categories: -* <> * <> * <> * <> @@ -31,45 +30,11 @@ grouped in the following categories: * <> -- -[[exported-fields-apm]] -== General APM fields - -Fields common to various APM events. - - - -*`data_stream.type`*:: -+ --- -Data stream type: logs, metrics, or traces. - -type: keyword - -example: traces - --- - -*`data_stream.dataset`*:: -+ --- -Data stream dataset name. - -type: keyword - -example: backend_service - --- - -*`data_stream.namespace`*:: -+ --- -User-defined data stream namespace. - -type: keyword +[[exported-fields-apm-error]] +== APM Error fields -example: production +Error-specific data for APM --- *`processor.name`*:: + @@ -507,49 +472,6 @@ type: long -- -*`span.type`*:: -+ --- -Keyword of specific relevance in the service's domain (eg: 'db.postgresql.query', 'template.erb', 'cache', etc). - - -type: keyword - --- - -*`span.subtype`*:: -+ --- -A further sub-division of the type (e.g. postgresql, elasticsearch) - - -type: keyword - --- - -[float] -=== self_time - -Portion of the span's duration where no direct child was running - - - -*`span.self_time.count`*:: -+ --- -type: long - --- - - -*`span.self_time.sum.us`*:: -+ --- -type: long - --- - - *`trace.id`*:: + -- @@ -1281,27 +1203,6 @@ example: us-east1 -- - -*`event.outcome`*:: -+ --- -`event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. - - -type: keyword - -example: success - -{yes-icon} {ecs-ref}[ECS] field. - --- - -[[exported-fields-apm-error]] -== APM Error fields - -Error-specific data for APM - - [float] === error @@ -1440,576 +1341,4599 @@ type: keyword Profiling-specific data for APM. - -*`profile.id`*:: +*`processor.name`*:: + -- -Unique ID for the profile. -All samples within a profile will have the same profile ID. - +Processor name. type: keyword -- -*`profile.duration`*:: +*`processor.event`*:: + -- -Duration of the profile, in microseconds. -All samples within a profile will have the same duration. To aggregate durations, you should first group by the profile ID. - +Processor event. -type: long +type: keyword -- -*`profile.cpu.ns`*:: +*`timestamp.us`*:: + -- -Amount of CPU time profiled, in nanoseconds. +Timestamp of the event in microseconds since Unix epoch. type: long -- - -*`profile.samples.count`*:: +*`labels`*:: + -- -Number of profile samples for the profiling period. +A flat mapping of user-defined labels with string, boolean or number values. -type: long +type: object + +{yes-icon} {ecs-ref}[ECS] field. -- +[float] +=== service -*`profile.alloc_objects.count`*:: +Service fields. + + + +*`service.name`*:: + -- -Number of objects allocated since the process started. +Immutable name of the service emitting this event. -type: long +type: keyword --- +{yes-icon} {ecs-ref}[ECS] field. +-- -*`profile.alloc_space.bytes`*:: +*`service.version`*:: + -- -Amount of memory allocated, in bytes, since the process started. +Version of the service emitting this event. -type: long +type: keyword --- +{yes-icon} {ecs-ref}[ECS] field. +-- -*`profile.inuse_objects.count`*:: +*`service.environment`*:: + -- -Number of objects allocated and currently in use. +Service environment. -type: long +type: keyword -- -*`profile.inuse_space.bytes`*:: +*`service.node.name`*:: + -- -Amount of memory allocated, in bytes, and currently in use. +Unique meaningful name of the service node. -type: long +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. -- -*`profile.top.id`*:: +*`service.language.name`*:: + -- -Unique ID for the top stack frame in the context of its callers. +Name of the programming language used. type: keyword -- -*`profile.top.function`*:: +*`service.language.version`*:: + -- -Function name for the top stack frame. +Version of the programming language used. type: keyword -- -*`profile.top.filename`*:: + +*`service.runtime.name`*:: + -- -Source code filename for the top stack frame. +Name of the runtime used. type: keyword -- -*`profile.top.line`*:: +*`service.runtime.version`*:: + -- -Source code line number for the top stack frame. +Version of the runtime used. -type: long +type: keyword -- -*`profile.stack.id`*:: +*`service.framework.name`*:: + -- -Unique ID for a stack frame in the context of its callers. +Name of the framework used. type: keyword -- -*`profile.stack.function`*:: +*`service.framework.version`*:: + -- -Function name for a stack frame. +Version of the framework used. type: keyword -- -*`profile.stack.filename`*:: + +*`agent.name`*:: + -- -Source code filename for a stack frame. +Name of the agent used. type: keyword +{yes-icon} {ecs-ref}[ECS] field. + -- -*`profile.stack.line`*:: +*`agent.version`*:: + -- -Source code line number for a stack frame. +Version of the agent used. -type: long +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. -- -[[exported-fields-apm-sourcemap]] -== APM Sourcemap fields +*`agent.ephemeral_id`*:: ++ +-- +The Ephemeral ID identifies a running process. -Sourcemap files enriched with metadata +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. +-- [float] -=== service +=== container -Service fields. +Container fields are used for meta information about the specific container that is the source of information. These fields help correlate data based containers from any runtime. -*`sourcemap.service.name`*:: +*`container.id`*:: + -- -The name of the service this sourcemap belongs to. +Unique container id. type: keyword --- +{yes-icon} {ecs-ref}[ECS] field. -*`sourcemap.service.version`*:: -+ -- -Service version. +[float] +=== kubernetes -type: keyword +Kubernetes metadata reported by agents --- -*`sourcemap.bundle_filepath`*:: + +*`kubernetes.namespace`*:: + -- -Location of the sourcemap relative to the file requesting it. +Kubernetes namespace type: keyword -- -[[exported-fields-apm-span]] -== APM Span fields - -Span-specific data for APM. - -*`view spans`*:: +*`kubernetes.node.name`*:: + -- -format: url +Kubernetes node name + + +type: keyword -- -*`child.id`*:: +*`kubernetes.pod.name`*:: + -- -The ID(s)s of the child event(s). +Kubernetes pod name type: keyword -- - -*`span.id`*:: +*`kubernetes.pod.uid`*:: + -- -The ID of the span stored as hex encoded string. +Kubernetes Pod UID type: keyword -- -*`span.name`*:: +[float] +=== host + +Optional host fields. + + + +*`host.architecture`*:: + -- -Generic designation of a span in the scope of a transaction. +The architecture of the host the event was recorded on. type: keyword +{yes-icon} {ecs-ref}[ECS] field. + -- -*`span.action`*:: +*`host.hostname`*:: + -- -The specific kind of event within the sub-type represented by the span (e.g. query, connect) +The hostname of the host the event was recorded on. type: keyword --- +{yes-icon} {ecs-ref}[ECS] field. +-- -*`span.start.us`*:: +*`host.name`*:: + -- -Offset relative to the transaction's timestamp identifying the start of the span, in microseconds. +Name of the host the event was recorded on. It can contain same information as host.hostname or a name specified by the user. -type: long +type: keyword --- +{yes-icon} {ecs-ref}[ECS] field. +-- -*`span.duration.us`*:: +*`host.ip`*:: + -- -Duration of the span, in microseconds. +IP of the host that records the event. -type: long +type: ip --- +{yes-icon} {ecs-ref}[ECS] field. -*`span.sync`*:: -+ -- -Indicates whether the span was executed synchronously or asynchronously. +[float] +=== os -type: boolean +The OS fields contain information about the operating system. --- -*`span.db.link`*:: +*`host.os.platform`*:: + -- -Database link. +The platform of the host the event was recorded on. type: keyword --- +{yes-icon} {ecs-ref}[ECS] field. -*`span.db.rows_affected`*:: -+ -- -Number of rows affected by the database statement. +[float] +=== process + +Information pertaining to the running process where the data was collected -type: long + +*`process.args`*:: ++ -- +Process arguments. +May be filtered to protect sensitive information. -[float] -=== service +type: keyword -Destination service context +{yes-icon} {ecs-ref}[ECS] field. +-- -*`span.destination.service.type`*:: +*`process.pid`*:: + -- -Type of the destination service (e.g. 'db', 'elasticsearch'). Should typically be the same as span.type. +Numeric process ID of the service process. -type: keyword +type: long + +{yes-icon} {ecs-ref}[ECS] field. -- -*`span.destination.service.name`*:: +*`process.ppid`*:: + -- -Identifier for the destination service (e.g. 'http://elastic.co', 'elasticsearch', 'rabbitmq') +Numeric ID of the service's parent process. -type: keyword +type: long + +{yes-icon} {ecs-ref}[ECS] field. -- -*`span.destination.service.resource`*:: +*`process.title`*:: + -- -Identifier for the destination service resource being operated on (e.g. 'http://elastic.co:80', 'elasticsearch', 'rabbitmq/queue_name') +Service process title. type: keyword --- +{yes-icon} {ecs-ref}[ECS] field. +-- -*`span.message.queue.name`*:: +*`observer.listening`*:: + -- -Name of the message queue or topic where the message is published or received. +Address the server is listening on. type: keyword -- - -*`span.message.age.ms`*:: +*`observer.hostname`*:: + -- -Age of a message in milliseconds. +Hostname of the APM Server. -type: long +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. -- -[[exported-fields-apm-span-metrics-xpack]] -== APM Span Metrics fields +*`observer.version`*:: ++ +-- +APM Server version. -APM span metrics are used for showing rate of requests and latency between instrumented services. +type: keyword +{yes-icon} {ecs-ref}[ECS] field. -*`metricset.period`*:: -+ -- -type: long +*`observer.version_major`*:: ++ -- +Major version number of the observer - -*`span.destination.service.response_time.count`*:: -+ --- -type: long +type: byte -- -*`span.destination.service.response_time.sum.us`*:: +*`observer.type`*:: + -- -type: long - --- +The type will be set to `apm-server`. -[[exported-fields-apm-transaction]] -== APM Transaction fields -Transaction-specific data for APM +type: keyword +{yes-icon} {ecs-ref}[ECS] field. +-- -*`transaction.duration.us`*:: +*`user.name`*:: + -- -Total duration of this transaction, in microseconds. +The username of the logged in user. -type: long +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. -- -*`transaction.result`*:: +*`user.id`*:: + -- -The result of the transaction. HTTP status code for HTTP-related transactions. +Identifier of the logged in user. type: keyword +{yes-icon} {ecs-ref}[ECS] field. + -- -*`transaction.marks`*:: +*`user.email`*:: + -- -A user-defined mapping of groups of marks in milliseconds. - +Email of the logged in user. -type: object --- +type: keyword -*`transaction.marks.*.*`*:: -+ --- -type: object +{yes-icon} {ecs-ref}[ECS] field. -- -*`transaction.experience.cls`*:: +*`client.ip`*:: + -- -The Cumulative Layout Shift metric - -type: scaled_float +IP address of the client of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. --- -*`transaction.experience.fid`*:: -+ --- -The First Input Delay metric +type: ip -type: scaled_float +{yes-icon} {ecs-ref}[ECS] field. -- -*`transaction.experience.tbt`*:: + +*`source.ip`*:: + -- -The Total Blocking Time metric +IP address of the source of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. -type: scaled_float + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. -- [float] -=== longtask +=== destination -Longtask duration/count metrics +Destination fields describe details about the destination of a packet/event. +Destination fields are usually populated in conjunction with source fields. -*`transaction.experience.longtask.count`*:: +*`destination.address`*:: + -- -The total number of of longtasks +Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. +Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. -type: long +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. -- -*`transaction.experience.longtask.sum`*:: +*`destination.ip`*:: + -- -The sum of longtask durations +IP addess of the destination. +Can be one of multiple IPv4 or IPv6 addresses. -type: scaled_float +type: ip + +{yes-icon} {ecs-ref}[ECS] field. -- -*`transaction.experience.longtask.max`*:: +*`destination.port`*:: + -- -The max longtask duration +Port of the destination. -type: scaled_float +type: long --- +format: string +{yes-icon} {ecs-ref}[ECS] field. -*`transaction.span_count.dropped`*:: -+ -- -The total amount of dropped spans for this transaction. -type: long +[float] +=== user_agent --- +The user_agent fields normally come from a browser request. They often show up in web service logs coming from the parsed user agent string. -*`transaction.message.queue.name`*:: +*`user_agent.original`*:: + -- -Name of the message queue or topic where the message is published or received. +Unparsed version of the user_agent. type: keyword --- +example: Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1 +{yes-icon} {ecs-ref}[ECS] field. -*`transaction.message.age.ms`*:: -+ -- -Age of a message in milliseconds. - - -type: long +*`user_agent.original.text`*:: ++ -- +Software agent acting in behalf of a user, eg. a web browser / OS combination. -[[exported-fields-apm-transaction-metrics]] -== APM Transaction Metrics fields - -APM transaction metrics, and transaction metrics-specific properties, such as transaction.root. +type: text +{yes-icon} {ecs-ref}[ECS] field. +-- -*`transaction.root`*:: +*`user_agent.name`*:: + -- -Identifies metrics for root transactions. This can be used for calculating metrics for traces. +Name of the user agent. + + +type: keyword + +example: Safari + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.version`*:: ++ +-- +Version of the user agent. + + +type: keyword + +example: 12.0 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== device + +Information concerning the device. + + + +*`user_agent.device.name`*:: ++ +-- +Name of the device. + + +type: keyword + +example: iPhone + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== os + +The OS fields contain information about the operating system. + + + +*`user_agent.os.platform`*:: ++ +-- +Operating system platform (such centos, ubuntu, windows). + + +type: keyword + +example: darwin + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.name`*:: ++ +-- +Operating system name, without the version. + + +type: keyword + +example: Mac OS X + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.full`*:: ++ +-- +Operating system name, including the version or code name. + + +type: keyword + +example: Mac OS Mojave + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.family`*:: ++ +-- +OS family (such as redhat, debian, freebsd, windows). + + +type: keyword + +example: debian + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.version`*:: ++ +-- +Operating system version as a raw string. + + +type: keyword + +example: 10.14.1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.kernel`*:: ++ +-- +Operating system kernel version as a raw string. + + +type: keyword + +example: 4.4.0-112-generic + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`experimental`*:: ++ +-- +Additional experimental data sent by the agents. + +type: object + +-- + +[float] +=== cloud + +Cloud metadata reported by agents + + + + +*`cloud.account.id`*:: ++ +-- +Cloud account ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.account.name`*:: ++ +-- +Cloud account name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.availability_zone`*:: ++ +-- +Cloud availability zone name + +type: keyword + +example: us-east1-a + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.instance.id`*:: ++ +-- +Cloud instance/machine ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.instance.name`*:: ++ +-- +Cloud instance/machine name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.machine.type`*:: ++ +-- +Cloud instance/machine type + +type: keyword + +example: t2.medium + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.project.id`*:: ++ +-- +Cloud project ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.project.name`*:: ++ +-- +Cloud project name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.provider`*:: ++ +-- +Cloud provider name + +type: keyword + +example: gcp + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.region`*:: ++ +-- +Cloud region name + +type: keyword + +example: us-east1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`profile.id`*:: ++ +-- +Unique ID for the profile. +All samples within a profile will have the same profile ID. + + +type: keyword + +-- + +*`profile.duration`*:: ++ +-- +Duration of the profile, in microseconds. +All samples within a profile will have the same duration. To aggregate durations, you should first group by the profile ID. + + +type: long + +-- + + +*`profile.cpu.ns`*:: ++ +-- +Amount of CPU time profiled, in nanoseconds. + + +type: long + +-- + + +*`profile.samples.count`*:: ++ +-- +Number of profile samples for the profiling period. + + +type: long + +-- + + +*`profile.alloc_objects.count`*:: ++ +-- +Number of objects allocated since the process started. + + +type: long + +-- + + +*`profile.alloc_space.bytes`*:: ++ +-- +Amount of memory allocated, in bytes, since the process started. + + +type: long + +-- + + +*`profile.inuse_objects.count`*:: ++ +-- +Number of objects allocated and currently in use. + + +type: long + +-- + + +*`profile.inuse_space.bytes`*:: ++ +-- +Amount of memory allocated, in bytes, and currently in use. + + +type: long + +-- + + +*`profile.top.id`*:: ++ +-- +Unique ID for the top stack frame in the context of its callers. + + +type: keyword + +-- + +*`profile.top.function`*:: ++ +-- +Function name for the top stack frame. + + +type: keyword + +-- + +*`profile.top.filename`*:: ++ +-- +Source code filename for the top stack frame. + + +type: keyword + +-- + +*`profile.top.line`*:: ++ +-- +Source code line number for the top stack frame. + + +type: long + +-- + + +*`profile.stack.id`*:: ++ +-- +Unique ID for a stack frame in the context of its callers. + + +type: keyword + +-- + +*`profile.stack.function`*:: ++ +-- +Function name for a stack frame. + + +type: keyword + +-- + +*`profile.stack.filename`*:: ++ +-- +Source code filename for a stack frame. + + +type: keyword + +-- + +*`profile.stack.line`*:: ++ +-- +Source code line number for a stack frame. + + +type: long + +-- + +[[exported-fields-apm-sourcemap]] +== APM Sourcemap fields + +Sourcemap files enriched with metadata + + + +[float] +=== service + +Service fields. + + + +*`sourcemap.service.name`*:: ++ +-- +The name of the service this sourcemap belongs to. + + +type: keyword + +-- + +*`sourcemap.service.version`*:: ++ +-- +Service version. + + +type: keyword + +-- + +*`sourcemap.bundle_filepath`*:: ++ +-- +Location of the sourcemap relative to the file requesting it. + + +type: keyword + +-- + +[[exported-fields-apm-span]] +== APM Span fields + +Span-specific data for APM. + + +*`processor.name`*:: ++ +-- +Processor name. + +type: keyword + +-- + +*`processor.event`*:: ++ +-- +Processor event. + +type: keyword + +-- + + +*`timestamp.us`*:: ++ +-- +Timestamp of the event in microseconds since Unix epoch. + + +type: long + +-- + +*`labels`*:: ++ +-- +A flat mapping of user-defined labels with string, boolean or number values. + + +type: object + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== service + +Service fields. + + + +*`service.name`*:: ++ +-- +Immutable name of the service emitting this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`service.version`*:: ++ +-- +Version of the service emitting this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`service.environment`*:: ++ +-- +Service environment. + + +type: keyword + +-- + + +*`service.node.name`*:: ++ +-- +Unique meaningful name of the service node. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`service.language.name`*:: ++ +-- +Name of the programming language used. + + +type: keyword + +-- + +*`service.language.version`*:: ++ +-- +Version of the programming language used. + + +type: keyword + +-- + + +*`service.runtime.name`*:: ++ +-- +Name of the runtime used. + + +type: keyword + +-- + +*`service.runtime.version`*:: ++ +-- +Version of the runtime used. + + +type: keyword + +-- + + +*`service.framework.name`*:: ++ +-- +Name of the framework used. + + +type: keyword + +-- + +*`service.framework.version`*:: ++ +-- +Version of the framework used. + + +type: keyword + +-- + + +*`transaction.id`*:: ++ +-- +The transaction ID. + + +type: keyword + +-- + +*`transaction.sampled`*:: ++ +-- +Transactions that are 'sampled' will include all available information. Transactions that are not sampled will not have spans or context. + + +type: boolean + +-- + +*`transaction.type`*:: ++ +-- +Keyword of specific relevance in the service's domain (eg. 'request', 'backgroundjob', etc) + + +type: keyword + +-- + +*`transaction.name`*:: ++ +-- +Generic designation of a transaction in the scope of a single service (eg. 'GET /users/:id'). + + +type: keyword + +-- + +*`transaction.name.text`*:: ++ +-- +type: text + +-- + + +*`transaction.duration.count`*:: ++ +-- +type: long + +-- + + +*`transaction.duration.sum.us`*:: ++ +-- +type: long + +-- + +[float] +=== self_time + +Portion of the transaction's duration where no direct child was running + + + +*`transaction.self_time.count`*:: ++ +-- +type: long + +-- + + +*`transaction.self_time.sum.us`*:: ++ +-- +type: long + +-- + +[float] +=== breakdown + +Counter for collected breakdowns for the transaction + + + +*`transaction.breakdown.count`*:: ++ +-- +type: long + +-- + + +*`span.id`*:: ++ +-- +The ID of the span stored as hex encoded string. + + +type: keyword + +-- + +*`span.name`*:: ++ +-- +Generic designation of a span in the scope of a transaction. + + +type: keyword + +-- + +*`span.action`*:: ++ +-- +The specific kind of event within the sub-type represented by the span (e.g. query, connect) + + +type: keyword + +-- + + +*`span.start.us`*:: ++ +-- +Offset relative to the transaction's timestamp identifying the start of the span, in microseconds. + + +type: long + +-- + + +*`span.duration.us`*:: ++ +-- +Duration of the span, in microseconds. + + +type: long + +-- + +*`span.sync`*:: ++ +-- +Indicates whether the span was executed synchronously or asynchronously. + + +type: boolean + +-- + + +*`span.db.link`*:: ++ +-- +Database link. + + +type: keyword + +-- + +*`span.db.rows_affected`*:: ++ +-- +Number of rows affected by the database statement. + + +type: long + +-- + + +[float] +=== service + +Destination service context + + +*`span.destination.service.type`*:: ++ +-- +Type of the destination service (e.g. 'db', 'elasticsearch'). Should typically be the same as span.type. + + +type: keyword + +-- + +*`span.destination.service.name`*:: ++ +-- +Identifier for the destination service (e.g. 'http://elastic.co', 'elasticsearch', 'rabbitmq') + + +type: keyword + +-- + +*`span.destination.service.resource`*:: ++ +-- +Identifier for the destination service resource being operated on (e.g. 'http://elastic.co:80', 'elasticsearch', 'rabbitmq/queue_name') + + +type: keyword + +-- + + + +*`span.message.queue.name`*:: ++ +-- +Name of the message queue or topic where the message is published or received. + + +type: keyword + +-- + + +*`span.message.age.ms`*:: ++ +-- +Age of a message in milliseconds. + + +type: long + +-- + + +*`trace.id`*:: ++ +-- +The ID of the trace to which the event belongs to. + + +type: keyword + +-- + + +*`parent.id`*:: ++ +-- +The ID of the parent event. + + +type: keyword + +-- + + +*`agent.name`*:: ++ +-- +Name of the agent used. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`agent.version`*:: ++ +-- +Version of the agent used. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`agent.ephemeral_id`*:: ++ +-- +The Ephemeral ID identifies a running process. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== container + +Container fields are used for meta information about the specific container that is the source of information. These fields help correlate data based containers from any runtime. + + + +*`container.id`*:: ++ +-- +Unique container id. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== kubernetes + +Kubernetes metadata reported by agents + + + +*`kubernetes.namespace`*:: ++ +-- +Kubernetes namespace + + +type: keyword + +-- + + +*`kubernetes.node.name`*:: ++ +-- +Kubernetes node name + + +type: keyword + +-- + + +*`kubernetes.pod.name`*:: ++ +-- +Kubernetes pod name + + +type: keyword + +-- + +*`kubernetes.pod.uid`*:: ++ +-- +Kubernetes Pod UID + + +type: keyword + +-- + +[float] +=== host + +Optional host fields. + + + +*`host.architecture`*:: ++ +-- +The architecture of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.hostname`*:: ++ +-- +The hostname of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.name`*:: ++ +-- +Name of the host the event was recorded on. It can contain same information as host.hostname or a name specified by the user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.ip`*:: ++ +-- +IP of the host that records the event. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== os + +The OS fields contain information about the operating system. + + + +*`host.os.platform`*:: ++ +-- +The platform of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== process + +Information pertaining to the running process where the data was collected + + + +*`process.args`*:: ++ +-- +Process arguments. +May be filtered to protect sensitive information. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.pid`*:: ++ +-- +Numeric process ID of the service process. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.ppid`*:: ++ +-- +Numeric ID of the service's parent process. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.title`*:: ++ +-- +Service process title. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`observer.listening`*:: ++ +-- +Address the server is listening on. + + +type: keyword + +-- + +*`observer.hostname`*:: ++ +-- +Hostname of the APM Server. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`observer.version`*:: ++ +-- +APM Server version. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`observer.version_major`*:: ++ +-- +Major version number of the observer + + +type: byte + +-- + +*`observer.type`*:: ++ +-- +The type will be set to `apm-server`. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`user.name`*:: ++ +-- +The username of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user.id`*:: ++ +-- +Identifier of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user.email`*:: ++ +-- +Email of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`client.ip`*:: ++ +-- +IP address of the client of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`source.ip`*:: ++ +-- +IP address of the source of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== destination + +Destination fields describe details about the destination of a packet/event. +Destination fields are usually populated in conjunction with source fields. + + +*`destination.address`*:: ++ +-- +Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. +Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`destination.ip`*:: ++ +-- +IP addess of the destination. +Can be one of multiple IPv4 or IPv6 addresses. + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`destination.port`*:: ++ +-- +Port of the destination. + +type: long + +format: string + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== user_agent + +The user_agent fields normally come from a browser request. They often show up in web service logs coming from the parsed user agent string. + + + +*`user_agent.original`*:: ++ +-- +Unparsed version of the user_agent. + + +type: keyword + +example: Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.original.text`*:: ++ +-- +Software agent acting in behalf of a user, eg. a web browser / OS combination. + + +type: text + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.name`*:: ++ +-- +Name of the user agent. + + +type: keyword + +example: Safari + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.version`*:: ++ +-- +Version of the user agent. + + +type: keyword + +example: 12.0 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== device + +Information concerning the device. + + + +*`user_agent.device.name`*:: ++ +-- +Name of the device. + + +type: keyword + +example: iPhone + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== os + +The OS fields contain information about the operating system. + + + +*`user_agent.os.platform`*:: ++ +-- +Operating system platform (such centos, ubuntu, windows). + + +type: keyword + +example: darwin + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.name`*:: ++ +-- +Operating system name, without the version. + + +type: keyword + +example: Mac OS X + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.full`*:: ++ +-- +Operating system name, including the version or code name. + + +type: keyword + +example: Mac OS Mojave + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.family`*:: ++ +-- +OS family (such as redhat, debian, freebsd, windows). + + +type: keyword + +example: debian + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.version`*:: ++ +-- +Operating system version as a raw string. + + +type: keyword + +example: 10.14.1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.kernel`*:: ++ +-- +Operating system kernel version as a raw string. + + +type: keyword + +example: 4.4.0-112-generic + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`experimental`*:: ++ +-- +Additional experimental data sent by the agents. + +type: object + +-- + +[float] +=== cloud + +Cloud metadata reported by agents + + + + +*`cloud.account.id`*:: ++ +-- +Cloud account ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.account.name`*:: ++ +-- +Cloud account name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.availability_zone`*:: ++ +-- +Cloud availability zone name + +type: keyword + +example: us-east1-a + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.instance.id`*:: ++ +-- +Cloud instance/machine ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.instance.name`*:: ++ +-- +Cloud instance/machine name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.machine.type`*:: ++ +-- +Cloud instance/machine type + +type: keyword + +example: t2.medium + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.project.id`*:: ++ +-- +Cloud project ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.project.name`*:: ++ +-- +Cloud project name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.provider`*:: ++ +-- +Cloud provider name + +type: keyword + +example: gcp + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.region`*:: ++ +-- +Cloud region name + +type: keyword + +example: us-east1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`event.outcome`*:: ++ +-- +`event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. + + +type: keyword + +example: success + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`view spans`*:: ++ +-- +format: url + +-- + + +*`child.id`*:: ++ +-- +The ID(s)s of the child event(s). + + +type: keyword + +-- + +[[exported-fields-apm-span-metrics-xpack]] +== APM Span Metrics fields + +APM span metrics are used for showing rate of requests and latency between instrumented services. + + + +*`metricset.period`*:: ++ +-- +type: long + +-- + + + +*`span.destination.service.response_time.count`*:: ++ +-- +type: long + +-- + +*`span.destination.service.response_time.sum.us`*:: ++ +-- +type: long + +-- + +[[exported-fields-apm-transaction]] +== APM Transaction fields + +Transaction-specific data for APM + + +*`processor.name`*:: ++ +-- +Processor name. + +type: keyword + +-- + +*`processor.event`*:: ++ +-- +Processor event. + +type: keyword + +-- + + +*`timestamp.us`*:: ++ +-- +Timestamp of the event in microseconds since Unix epoch. + + +type: long + +-- + +[float] +=== url + +A complete Url, with scheme, host and path. + + + +*`url.scheme`*:: ++ +-- +The protocol of the request, e.g. "https:". + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`url.full`*:: ++ +-- +The full, possibly agent-assembled URL of the request, e.g https://example.com:443/search?q=elasticsearch#top. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`url.domain`*:: ++ +-- +The hostname of the request, e.g. "example.com". + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`url.port`*:: ++ +-- +The port of the request, e.g. 443. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`url.path`*:: ++ +-- +The path of the request, e.g. "/search". + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`url.query`*:: ++ +-- +The query string of the request, e.g. "q=elasticsearch". + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`url.fragment`*:: ++ +-- +A fragment specifying a location in a web page , e.g. "top". + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`http.version`*:: ++ +-- +The http version of the request leading to this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`http.request.method`*:: ++ +-- +The http method of the request leading to this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`http.request.headers`*:: ++ +-- +The canonical headers of the monitored HTTP request. + + +type: object + +Object is not enabled. + +-- + +*`http.request.referrer`*:: ++ +-- +Referrer for this HTTP request. + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`http.response.status_code`*:: ++ +-- +The status code of the HTTP response. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`http.response.finished`*:: ++ +-- +Used by the Node agent to indicate when in the response life cycle an error has occurred. + + +type: boolean + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`http.response.headers`*:: ++ +-- +The canonical headers of the monitored HTTP response. + + +type: object + +Object is not enabled. + +-- + +*`labels`*:: ++ +-- +A flat mapping of user-defined labels with string, boolean or number values. + + +type: object + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== service + +Service fields. + + + +*`service.name`*:: ++ +-- +Immutable name of the service emitting this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`service.version`*:: ++ +-- +Version of the service emitting this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`service.environment`*:: ++ +-- +Service environment. + + +type: keyword + +-- + + +*`service.node.name`*:: ++ +-- +Unique meaningful name of the service node. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`service.language.name`*:: ++ +-- +Name of the programming language used. + + +type: keyword + +-- + +*`service.language.version`*:: ++ +-- +Version of the programming language used. + + +type: keyword + +-- + + +*`service.runtime.name`*:: ++ +-- +Name of the runtime used. + + +type: keyword + +-- + +*`service.runtime.version`*:: ++ +-- +Version of the runtime used. + + +type: keyword + +-- + + +*`service.framework.name`*:: ++ +-- +Name of the framework used. + + +type: keyword + +-- + +*`service.framework.version`*:: ++ +-- +Version of the framework used. + + +type: keyword + +-- + + + +*`transaction.duration.us`*:: ++ +-- +Total duration of this transaction, in microseconds. + + +type: long + +-- + +*`transaction.result`*:: ++ +-- +The result of the transaction. HTTP status code for HTTP-related transactions. + + +type: keyword + +-- + +*`transaction.marks`*:: ++ +-- +A user-defined mapping of groups of marks in milliseconds. + + +type: object + +-- + +*`transaction.marks.*.*`*:: ++ +-- +type: object + +-- + + +*`transaction.experience.cls`*:: ++ +-- +The Cumulative Layout Shift metric + +type: scaled_float + +-- + +*`transaction.experience.fid`*:: ++ +-- +The First Input Delay metric + +type: scaled_float + +-- + +*`transaction.experience.tbt`*:: ++ +-- +The Total Blocking Time metric + +type: scaled_float + +-- + +[float] +=== longtask + +Longtask duration/count metrics + + +*`transaction.experience.longtask.count`*:: ++ +-- +The total number of of longtasks + +type: long + +-- + +*`transaction.experience.longtask.sum`*:: ++ +-- +The sum of longtask durations + +type: scaled_float + +-- + +*`transaction.experience.longtask.max`*:: ++ +-- +The max longtask duration + +type: scaled_float + +-- + + +*`transaction.span_count.dropped`*:: ++ +-- +The total amount of dropped spans for this transaction. + +type: long + +-- + + + +*`transaction.message.queue.name`*:: ++ +-- +Name of the message queue or topic where the message is published or received. + + +type: keyword + +-- + + +*`transaction.message.age.ms`*:: ++ +-- +Age of a message in milliseconds. + + +type: long + +-- + + +*`span.type`*:: ++ +-- +Keyword of specific relevance in the service's domain (eg: 'db.postgresql.query', 'template.erb', 'cache', etc). + + +type: keyword + +-- + +*`span.subtype`*:: ++ +-- +A further sub-division of the type (e.g. postgresql, elasticsearch) + + +type: keyword + +-- + +[float] +=== self_time + +Portion of the span's duration where no direct child was running + + + +*`span.self_time.count`*:: ++ +-- +type: long + +-- + + +*`span.self_time.sum.us`*:: ++ +-- +type: long + +-- + + +*`trace.id`*:: ++ +-- +The ID of the trace to which the event belongs to. + + +type: keyword + +-- + + +*`parent.id`*:: ++ +-- +The ID of the parent event. + + +type: keyword + +-- + + +*`agent.name`*:: ++ +-- +Name of the agent used. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`agent.version`*:: ++ +-- +Version of the agent used. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`agent.ephemeral_id`*:: ++ +-- +The Ephemeral ID identifies a running process. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== container + +Container fields are used for meta information about the specific container that is the source of information. These fields help correlate data based containers from any runtime. + + + +*`container.id`*:: ++ +-- +Unique container id. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== kubernetes + +Kubernetes metadata reported by agents + + + +*`kubernetes.namespace`*:: ++ +-- +Kubernetes namespace + + +type: keyword + +-- + + +*`kubernetes.node.name`*:: ++ +-- +Kubernetes node name + + +type: keyword + +-- + + +*`kubernetes.pod.name`*:: ++ +-- +Kubernetes pod name + + +type: keyword + +-- + +*`kubernetes.pod.uid`*:: ++ +-- +Kubernetes Pod UID + + +type: keyword + +-- + +[float] +=== host + +Optional host fields. + + + +*`host.architecture`*:: ++ +-- +The architecture of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.hostname`*:: ++ +-- +The hostname of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.name`*:: ++ +-- +Name of the host the event was recorded on. It can contain same information as host.hostname or a name specified by the user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.ip`*:: ++ +-- +IP of the host that records the event. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== os + +The OS fields contain information about the operating system. + + + +*`host.os.platform`*:: ++ +-- +The platform of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== process + +Information pertaining to the running process where the data was collected + + + +*`process.args`*:: ++ +-- +Process arguments. +May be filtered to protect sensitive information. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.pid`*:: ++ +-- +Numeric process ID of the service process. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.ppid`*:: ++ +-- +Numeric ID of the service's parent process. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.title`*:: ++ +-- +Service process title. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`observer.listening`*:: ++ +-- +Address the server is listening on. + + +type: keyword + +-- + +*`observer.hostname`*:: ++ +-- +Hostname of the APM Server. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`observer.version`*:: ++ +-- +APM Server version. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`observer.version_major`*:: ++ +-- +Major version number of the observer + + +type: byte + +-- + +*`observer.type`*:: ++ +-- +The type will be set to `apm-server`. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`user.name`*:: ++ +-- +The username of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user.id`*:: ++ +-- +Identifier of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user.email`*:: ++ +-- +Email of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`client.ip`*:: ++ +-- +IP address of the client of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`source.ip`*:: ++ +-- +IP address of the source of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== destination + +Destination fields describe details about the destination of a packet/event. +Destination fields are usually populated in conjunction with source fields. + + +*`destination.address`*:: ++ +-- +Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. +Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`destination.ip`*:: ++ +-- +IP addess of the destination. +Can be one of multiple IPv4 or IPv6 addresses. + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`destination.port`*:: ++ +-- +Port of the destination. + +type: long + +format: string + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== user_agent + +The user_agent fields normally come from a browser request. They often show up in web service logs coming from the parsed user agent string. + + + +*`user_agent.original`*:: ++ +-- +Unparsed version of the user_agent. + + +type: keyword + +example: Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.original.text`*:: ++ +-- +Software agent acting in behalf of a user, eg. a web browser / OS combination. + + +type: text + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.name`*:: ++ +-- +Name of the user agent. + + +type: keyword + +example: Safari + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.version`*:: ++ +-- +Version of the user agent. + + +type: keyword + +example: 12.0 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== device + +Information concerning the device. + + + +*`user_agent.device.name`*:: ++ +-- +Name of the device. + + +type: keyword + +example: iPhone + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== os + +The OS fields contain information about the operating system. + + + +*`user_agent.os.platform`*:: ++ +-- +Operating system platform (such centos, ubuntu, windows). + + +type: keyword + +example: darwin + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.name`*:: ++ +-- +Operating system name, without the version. + + +type: keyword + +example: Mac OS X + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.full`*:: ++ +-- +Operating system name, including the version or code name. + + +type: keyword + +example: Mac OS Mojave + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.family`*:: ++ +-- +OS family (such as redhat, debian, freebsd, windows). + + +type: keyword + +example: debian + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.version`*:: ++ +-- +Operating system version as a raw string. + + +type: keyword + +example: 10.14.1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.kernel`*:: ++ +-- +Operating system kernel version as a raw string. + + +type: keyword + +example: 4.4.0-112-generic + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`experimental`*:: ++ +-- +Additional experimental data sent by the agents. + +type: object + +-- + +[float] +=== cloud + +Cloud metadata reported by agents + + + + +*`cloud.account.id`*:: ++ +-- +Cloud account ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.account.name`*:: ++ +-- +Cloud account name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.availability_zone`*:: ++ +-- +Cloud availability zone name + +type: keyword + +example: us-east1-a + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.instance.id`*:: ++ +-- +Cloud instance/machine ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.instance.name`*:: ++ +-- +Cloud instance/machine name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.machine.type`*:: ++ +-- +Cloud instance/machine type + +type: keyword + +example: t2.medium + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.project.id`*:: ++ +-- +Cloud project ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.project.name`*:: ++ +-- +Cloud project name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.provider`*:: ++ +-- +Cloud provider name + +type: keyword + +example: gcp + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.region`*:: ++ +-- +Cloud region name + +type: keyword + +example: us-east1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`event.outcome`*:: ++ +-- +`event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. + + +type: keyword + +example: success + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[[exported-fields-apm-transaction-metrics]] +== APM Transaction Metrics fields + +APM transaction metrics, and transaction metrics-specific properties, such as transaction.root. + + + +*`processor.name`*:: ++ +-- +Processor name. + +type: keyword + +-- + +*`processor.event`*:: ++ +-- +Processor event. + +type: keyword + +-- + + +*`timestamp.us`*:: ++ +-- +Timestamp of the event in microseconds since Unix epoch. + + +type: long + +-- + +*`labels`*:: ++ +-- +A flat mapping of user-defined labels with string, boolean or number values. + + +type: object + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== service + +Service fields. + + + +*`service.name`*:: ++ +-- +Immutable name of the service emitting this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`service.version`*:: ++ +-- +Version of the service emitting this event. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`service.environment`*:: ++ +-- +Service environment. + + +type: keyword + +-- + + +*`service.node.name`*:: ++ +-- +Unique meaningful name of the service node. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`service.language.name`*:: ++ +-- +Name of the programming language used. + + +type: keyword + +-- + +*`service.language.version`*:: ++ +-- +Version of the programming language used. + + +type: keyword + +-- + + +*`service.runtime.name`*:: ++ +-- +Name of the runtime used. + + +type: keyword + +-- + +*`service.runtime.version`*:: ++ +-- +Version of the runtime used. + + +type: keyword + +-- + + +*`service.framework.name`*:: ++ +-- +Name of the framework used. + + +type: keyword + +-- + +*`service.framework.version`*:: ++ +-- +Version of the framework used. + + +type: keyword + +-- + + +*`transaction.id`*:: ++ +-- +The transaction ID. + + +type: keyword + +-- + +*`transaction.sampled`*:: ++ +-- +Transactions that are 'sampled' will include all available information. Transactions that are not sampled will not have spans or context. + + +type: boolean + +-- + +*`transaction.type`*:: ++ +-- +Keyword of specific relevance in the service's domain (eg. 'request', 'backgroundjob', etc) + + +type: keyword + +-- + +*`transaction.name`*:: ++ +-- +Generic designation of a transaction in the scope of a single service (eg. 'GET /users/:id'). + + +type: keyword + +-- + +*`transaction.name.text`*:: ++ +-- +type: text + +-- + + +*`transaction.duration.count`*:: ++ +-- +type: long + +-- + + +*`transaction.duration.sum.us`*:: ++ +-- +type: long + +-- + +[float] +=== self_time + +Portion of the transaction's duration where no direct child was running + + + +*`transaction.self_time.count`*:: ++ +-- +type: long + +-- + + +*`transaction.self_time.sum.us`*:: ++ +-- +type: long + +-- + +[float] +=== breakdown + +Counter for collected breakdowns for the transaction + + + +*`transaction.breakdown.count`*:: ++ +-- +type: long + +-- + +*`transaction.root`*:: ++ +-- +Identifies metrics for root transactions. This can be used for calculating metrics for traces. type: boolean -- + +*`span.type`*:: ++ +-- +Keyword of specific relevance in the service's domain (eg: 'db.postgresql.query', 'template.erb', 'cache', etc). + + +type: keyword + +-- + +*`span.subtype`*:: ++ +-- +A further sub-division of the type (e.g. postgresql, elasticsearch) + + +type: keyword + +-- + +[float] +=== self_time + +Portion of the span's duration where no direct child was running + + + +*`span.self_time.count`*:: ++ +-- +type: long + +-- + + +*`span.self_time.sum.us`*:: ++ +-- +type: long + +-- + + +*`agent.name`*:: ++ +-- +Name of the agent used. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`agent.version`*:: ++ +-- +Version of the agent used. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`agent.ephemeral_id`*:: ++ +-- +The Ephemeral ID identifies a running process. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== container + +Container fields are used for meta information about the specific container that is the source of information. These fields help correlate data based containers from any runtime. + + + +*`container.id`*:: ++ +-- +Unique container id. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== kubernetes + +Kubernetes metadata reported by agents + + + +*`kubernetes.namespace`*:: ++ +-- +Kubernetes namespace + + +type: keyword + +-- + + +*`kubernetes.node.name`*:: ++ +-- +Kubernetes node name + + +type: keyword + +-- + + +*`kubernetes.pod.name`*:: ++ +-- +Kubernetes pod name + + +type: keyword + +-- + +*`kubernetes.pod.uid`*:: ++ +-- +Kubernetes Pod UID + + +type: keyword + +-- + +[float] +=== host + +Optional host fields. + + + +*`host.architecture`*:: ++ +-- +The architecture of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.hostname`*:: ++ +-- +The hostname of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.name`*:: ++ +-- +Name of the host the event was recorded on. It can contain same information as host.hostname or a name specified by the user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`host.ip`*:: ++ +-- +IP of the host that records the event. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== os + +The OS fields contain information about the operating system. + + + +*`host.os.platform`*:: ++ +-- +The platform of the host the event was recorded on. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== process + +Information pertaining to the running process where the data was collected + + + +*`process.args`*:: ++ +-- +Process arguments. +May be filtered to protect sensitive information. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.pid`*:: ++ +-- +Numeric process ID of the service process. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.ppid`*:: ++ +-- +Numeric ID of the service's parent process. + + +type: long + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`process.title`*:: ++ +-- +Service process title. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`observer.listening`*:: ++ +-- +Address the server is listening on. + + +type: keyword + +-- + +*`observer.hostname`*:: ++ +-- +Hostname of the APM Server. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`observer.version`*:: ++ +-- +APM Server version. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`observer.version_major`*:: ++ +-- +Major version number of the observer + + +type: byte + +-- + +*`observer.type`*:: ++ +-- +The type will be set to `apm-server`. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`user.name`*:: ++ +-- +The username of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user.id`*:: ++ +-- +Identifier of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user.email`*:: ++ +-- +Email of the logged in user. + + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`client.ip`*:: ++ +-- +IP address of the client of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`source.ip`*:: ++ +-- +IP address of the source of a recorded event. This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== destination + +Destination fields describe details about the destination of a packet/event. +Destination fields are usually populated in conjunction with source fields. + + +*`destination.address`*:: ++ +-- +Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the `.address` field. +Then it should be duplicated to `.ip` or `.domain`, depending on which one it is. + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`destination.ip`*:: ++ +-- +IP addess of the destination. +Can be one of multiple IPv4 or IPv6 addresses. + +type: ip + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`destination.port`*:: ++ +-- +Port of the destination. + +type: long + +format: string + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== user_agent + +The user_agent fields normally come from a browser request. They often show up in web service logs coming from the parsed user agent string. + + + +*`user_agent.original`*:: ++ +-- +Unparsed version of the user_agent. + + +type: keyword + +example: Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.original.text`*:: ++ +-- +Software agent acting in behalf of a user, eg. a web browser / OS combination. + + +type: text + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.name`*:: ++ +-- +Name of the user agent. + + +type: keyword + +example: Safari + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.version`*:: ++ +-- +Version of the user agent. + + +type: keyword + +example: 12.0 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== device + +Information concerning the device. + + + +*`user_agent.device.name`*:: ++ +-- +Name of the device. + + +type: keyword + +example: iPhone + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +[float] +=== os + +The OS fields contain information about the operating system. + + + +*`user_agent.os.platform`*:: ++ +-- +Operating system platform (such centos, ubuntu, windows). + + +type: keyword + +example: darwin + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.name`*:: ++ +-- +Operating system name, without the version. + + +type: keyword + +example: Mac OS X + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.full`*:: ++ +-- +Operating system name, including the version or code name. + + +type: keyword + +example: Mac OS Mojave + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.family`*:: ++ +-- +OS family (such as redhat, debian, freebsd, windows). + + +type: keyword + +example: debian + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.version`*:: ++ +-- +Operating system version as a raw string. + + +type: keyword + +example: 10.14.1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`user_agent.os.kernel`*:: ++ +-- +Operating system kernel version as a raw string. + + +type: keyword + +example: 4.4.0-112-generic + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`experimental`*:: ++ +-- +Additional experimental data sent by the agents. + +type: object + +-- + +[float] +=== cloud + +Cloud metadata reported by agents + + + + +*`cloud.account.id`*:: ++ +-- +Cloud account ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.account.name`*:: ++ +-- +Cloud account name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.availability_zone`*:: ++ +-- +Cloud availability zone name + +type: keyword + +example: us-east1-a + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.instance.id`*:: ++ +-- +Cloud instance/machine ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.instance.name`*:: ++ +-- +Cloud instance/machine name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.machine.type`*:: ++ +-- +Cloud instance/machine type + +type: keyword + +example: t2.medium + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`cloud.project.id`*:: ++ +-- +Cloud project ID + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.project.name`*:: ++ +-- +Cloud project name + +type: keyword + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.provider`*:: ++ +-- +Cloud provider name + +type: keyword + +example: gcp + +{yes-icon} {ecs-ref}[ECS] field. + +-- + +*`cloud.region`*:: ++ +-- +Cloud region name + +type: keyword + +example: us-east1 + +{yes-icon} {ecs-ref}[ECS] field. + +-- + + +*`event.outcome`*:: ++ +-- +`event.outcome` simply denotes whether the event represents a success or a failure from the perspective of the entity that produced the event. + + +type: keyword + +example: success + +{yes-icon} {ecs-ref}[ECS] field. + +-- + [[exported-fields-apm-transaction-metrics-xpack]] == APM Transaction Metrics fields diff --git a/docs/spec/v2/metricset.json b/docs/spec/v2/metricset.json index 9bfc90d1564..bbd73837086 100644 --- a/docs/spec/v2/metricset.json +++ b/docs/spec/v2/metricset.json @@ -8,6 +8,10 @@ "additionalProperties": false, "patternProperties": { "^[^*\"]*$": { + "type": [ + "null", + "object" + ], "properties": { "value": { "description": "Value holds the value of a single metric sample.", diff --git a/go.mod b/go.mod index 81410ccf743..8b7846bf626 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,6 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.6.1 github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c - github.com/ua-parser/uap-go v0.0.0-20200325213135-e1c09f13e2fe github.com/uber/tchannel-go v1.16.0 // indirect github.com/urso/magetools v0.0.0-20200125210132-c2e338f92f3a // indirect github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56 diff --git a/go.sum b/go.sum index 7d0aaac5eb9..2df0f1cee58 100644 --- a/go.sum +++ b/go.sum @@ -963,8 +963,6 @@ github.com/tsg/go-daemon v0.0.0-20200207173439-e704b93fd89b/go.mod h1:jAqhj/JBVC github.com/tsg/gopacket v0.0.0-20200626092518-2ab8e397a786 h1:B/IVHYiI0d04dudYw+CvCAGqSMq8d0yWy56eD6p85BQ= github.com/tsg/gopacket v0.0.0-20200626092518-2ab8e397a786/go.mod h1:RIkfovP3Y7my19aXEjjbNd9E5TlHozzAyt7B8AaEcwg= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ua-parser/uap-go v0.0.0-20200325213135-e1c09f13e2fe h1:aj/vX5epIlQQBEocKoM9nSAiNpakdQzElc8SaRFPu+I= -github.com/ua-parser/uap-go v0.0.0-20200325213135-e1c09f13e2fe/go.mod h1:OBcG9bn7sHtXgarhUEb3OfCnNsgtGnkVf41ilSZ3K3E= github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.16.0+incompatible h1:Q2Pp6v3QYiocMxomCaJuwQGFt7E53bPYqEgug/AoBtY= diff --git a/idxmgmt/supporter.go b/idxmgmt/supporter.go index e8a8f676f31..eeffdcee412 100644 --- a/idxmgmt/supporter.go +++ b/idxmgmt/supporter.go @@ -54,7 +54,7 @@ type supporter struct { dataStreams bool templateConfig template.TemplateConfig ilmConfig ilm.Config - unmanagedIdxConfig *unmanaged.Config + unmanagedIdxConfig unmanaged.Config migration bool ilmSupporters []libilm.Supporter @@ -91,21 +91,10 @@ type ilmIndexSelector struct { func newSupporter(log *logp.Logger, info beat.Info, cfg *IndexManagementConfig) (*supporter, error) { var ( - unmanagedIdxCfg unmanaged.Config - mode = cfg.ILM.Mode - st = indexState{} + mode = cfg.ILM.Mode + st = indexState{} ) - if cfg.Output.Name() == esKey { - if err := cfg.Output.Config().Unpack(&unmanagedIdxCfg); err != nil { - return nil, fmt.Errorf("unpacking output elasticsearch index config fails: %+v", err) - } - - if err := checkTemplateESSettings(cfg.Template, &unmanagedIdxCfg); err != nil { - return nil, err - } - } - var disableILM bool if cfg.Output.Name() != esKey || cfg.ILM.Mode == libilm.ModeDisabled { disableILM = true @@ -113,7 +102,7 @@ func newSupporter(log *logp.Logger, info beat.Info, cfg *IndexManagementConfig) // ILM is set to "auto": disable if we're using data streams, // or if we're not using data streams but we're using customised, // unmanaged indices. - if cfg.DataStreams || unmanagedIdxCfg.Customized() { + if cfg.DataStreams || cfg.unmanagedIdxCfg.Customized() { disableILM = true } } @@ -133,7 +122,7 @@ func newSupporter(log *logp.Logger, info beat.Info, cfg *IndexManagementConfig) dataStreams: cfg.DataStreams, templateConfig: cfg.Template, ilmConfig: cfg.ILM, - unmanagedIdxConfig: &unmanagedIdxCfg, + unmanagedIdxConfig: cfg.unmanagedIdxCfg, migration: false, st: st, ilmSupporters: ilmSupporters, @@ -277,14 +266,3 @@ func getEventCustomIndex(evt *beat.Event) string { return "" } - -func checkTemplateESSettings(tmplCfg template.TemplateConfig, indexCfg *unmanaged.Config) error { - if !tmplCfg.Enabled || indexCfg == nil { - return nil - } - - if indexCfg.Index != "" && (tmplCfg.Name == "" || tmplCfg.Pattern == "") { - return errors.New("`setup.template.name` and `setup.template.pattern` have to be set if `output.elasticsearch` index name is modified") - } - return nil -} diff --git a/idxmgmt/supporter_factory.go b/idxmgmt/supporter_factory.go index 9c8c801f6c4..0c826286b3e 100644 --- a/idxmgmt/supporter_factory.go +++ b/idxmgmt/supporter_factory.go @@ -18,7 +18,7 @@ package idxmgmt import ( - "fmt" + "github.com/pkg/errors" "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common" @@ -27,16 +27,17 @@ import ( "github.com/elastic/beats/v7/libbeat/template" "github.com/elastic/apm-server/idxmgmt/ilm" + "github.com/elastic/apm-server/idxmgmt/unmanaged" logs "github.com/elastic/apm-server/log" ) -// functionality largely copied from libbeat - type IndexManagementConfig struct { DataStreams bool Template template.TemplateConfig ILM ilm.Config Output common.ConfigNamespace + + unmanagedIdxCfg unmanaged.Config } // MakeDefaultSupporter creates a new idxmgmt.Supporter, using the given root config. @@ -56,50 +57,89 @@ func MakeDefaultSupporter(log *logp.Logger, info beat.Info, configRoot *common.C if err != nil { return nil, err } + log = namedLogger(log) + return newSupporter(log, info, cfg) +} + +func namedLogger(log *logp.Logger) *logp.Logger { if log == nil { - log = logp.NewLogger(logs.IndexManagement) - } else { - log = log.Named(logs.IndexManagement) + return logp.NewLogger(logs.IndexManagement) } - return newSupporter(log, info, cfg) + return log.Named(logs.IndexManagement) } +// NewIndexManagementConfig extracts and validates index management config from info and configRoot. func NewIndexManagementConfig(info beat.Info, configRoot *common.Config) (*IndexManagementConfig, error) { - cfg := struct { - DataStreams *common.Config `config:"apm-server.data_streams"` - ILM *common.Config `config:"apm-server.ilm"` - Template *common.Config `config:"setup.template"` - Output common.ConfigNamespace `config:"output"` - }{} + var cfg struct { + DataStreams *common.Config `config:"apm-server.data_streams"` + RegisterIngestPipeline *common.Config `config:"apm-server.register.ingest.pipeline"` + ILM *common.Config `config:"apm-server.ilm"` + Template *common.Config `config:"setup.template"` + Output common.ConfigNamespace `config:"output"` + } if configRoot != nil { if err := configRoot.Unpack(&cfg); err != nil { return nil, err } } - tmplConfig, err := unpackTemplateConfig(cfg.Template) + templateConfig, err := unpackTemplateConfig(cfg.Template) if err != nil { - return nil, fmt.Errorf("unpacking template config fails: %+v", err) + return nil, errors.Wrap(err, "unpacking template config failed") } ilmConfig, err := ilm.NewConfig(info, cfg.ILM) if err != nil { - return nil, fmt.Errorf("creating ILM config fails: %v", err) + return nil, errors.Wrap(err, "creating ILM config fails") + } + + var unmanagedIdxCfg unmanaged.Config + if cfg.Output.Name() == esKey { + if err := cfg.Output.Config().Unpack(&unmanagedIdxCfg); err != nil { + return nil, errors.Wrap(err, "failed to unpack output.elasticsearch config") + } + if err := checkTemplateESSettings(templateConfig, &unmanagedIdxCfg); err != nil { + return nil, err + } } return &IndexManagementConfig{ - DataStreams: cfg.DataStreams.Enabled(), - Template: tmplConfig, - ILM: ilmConfig, - Output: cfg.Output, + Output: cfg.Output, + Template: templateConfig, + ILM: ilmConfig, + + unmanagedIdxCfg: unmanagedIdxCfg, }, nil } -func unpackTemplateConfig(cfg *common.Config) (template.TemplateConfig, error) { - config := template.DefaultConfig() - if cfg == nil { - return config, nil +func checkTemplateESSettings(tmplCfg template.TemplateConfig, indexCfg *unmanaged.Config) error { + if !tmplCfg.Enabled || indexCfg == nil { + return nil + } + if indexCfg.Index != "" && (tmplCfg.Name == "" || tmplCfg.Pattern == "") { + return errors.New("`setup.template.name` and `setup.template.pattern` have to be set if `output.elasticsearch` index name is modified") + } + return nil +} + +// unpackTemplateConfig merges APM-specific template settings with (possibly nil) +// user-defined config, unpacks it over template.DefaultConfig(), returning the result. +func unpackTemplateConfig(userTemplateConfig *common.Config) (template.TemplateConfig, error) { + templateConfig := common.MustNewConfigFrom(` +settings: + index: + codec: best_compression + mapping.total_fields.limit: 2000 + number_of_shards: 1 + _source.enabled: true`) + if userTemplateConfig != nil { + if err := templateConfig.Merge(userTemplateConfig); err != nil { + return template.TemplateConfig{}, errors.Wrap(err, "merging failed") + } + } + out := template.DefaultConfig() + if err := templateConfig.Unpack(&out); err != nil { + return template.TemplateConfig{}, err } - err := cfg.Unpack(&config) - return config, err + return out, nil } diff --git a/idxmgmt/supporter_factory_test.go b/idxmgmt/supporter_factory_test.go index 132007d303f..e8f0a4841ce 100644 --- a/idxmgmt/supporter_factory_test.go +++ b/idxmgmt/supporter_factory_test.go @@ -55,9 +55,10 @@ func TestMakeDefaultSupporter(t *testing.T) { assert.True(t, s.Enabled()) assert.NotNil(t, s.log) assert.True(t, s.templateConfig.Enabled) + assert.Equal(t, "best_compression", s.templateConfig.Settings.Index["codec"]) assert.Equal(t, libilm.ModeAuto, s.ilmConfig.Mode) assert.True(t, s.ilmConfig.Setup.Enabled) - assert.Equal(t, &unmanaged.Config{}, s.unmanagedIdxConfig) + assert.Equal(t, unmanaged.Config{}, s.unmanagedIdxConfig) }) t.Run("ILMDisabled", func(t *testing.T) { @@ -73,6 +74,7 @@ func TestMakeDefaultSupporter(t *testing.T) { assert.Equal(t, libilm.ModeDisabled, s.ilmConfig.Mode) assert.True(t, s.ilmConfig.Setup.Enabled) }) + t.Run("SetupTemplateConfigConflicting", func(t *testing.T) { s, err := buildSupporter(map[string]interface{}{ "output.elasticsearch.index": "custom-index", @@ -80,6 +82,6 @@ func TestMakeDefaultSupporter(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "`setup.template.name` and `setup.template.pattern` have to be set ") assert.Nil(t, s) - }) + } diff --git a/include/fields.go b/include/fields.go index 488e242db46..15e662b3afc 100644 --- a/include/fields.go +++ b/include/fields.go @@ -32,5 +32,5 @@ func init() { // AssetBuildFieldsFieldsYml returns asset data. // This is the base64 encoded gzipped contents of build/fields/fields.yml. func AssetBuildFieldsFieldsYml() string { - return "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" + return "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" } diff --git a/model/error/_meta/fields.yml b/model/error/_meta/fields.yml index 13d432715e0..8975da87a7d 100644 --- a/model/error/_meta/fields.yml +++ b/model/error/_meta/fields.yml @@ -2,6 +2,752 @@ title: APM Error description: Error-specific data for APM fields: + - name: processor.name + type: keyword + description: Processor name. + + - name: processor.event + type: keyword + description: Processor event. + + - name: timestamp + type: group + fields: + - name: us + type: long + count: 1 + description: > + Timestamp of the event in microseconds since Unix epoch. + + - name: url + type: group + description: > + A complete Url, with scheme, host and path. + dynamic: false + fields: + + - name: scheme + type: keyword + description: > + The protocol of the request, e.g. "https:". + overwrite: true + + - name: full + type: keyword + description: > + The full, possibly agent-assembled URL of the request, e.g https://example.com:443/search?q=elasticsearch#top. + overwrite: true + + - name: domain + type: keyword + description: > + The hostname of the request, e.g. "example.com". + overwrite: true + + - name: port + type: long + description: > + The port of the request, e.g. 443. + overwrite: true + + - name: path + type: keyword + description: > + The path of the request, e.g. "/search". + overwrite: true + + - name: query + type: keyword + description: > + The query string of the request, e.g. "q=elasticsearch". + overwrite: true + + - name: fragment + type: keyword + description: > + A fragment specifying a location in a web page , e.g. "top". + overwrite: true + + - name: http + type: group + dynamic: false + fields: + + - name: version + type: keyword + description: > + The http version of the request leading to this event. + overwrite: true + + - name: request + type: group + fields: + + - name: method + type: keyword + description: > + The http method of the request leading to this event. + overwrite: true + + - name: headers + type: object + enabled: false + description: > + The canonical headers of the monitored HTTP request. + + - name: referrer + type: keyword + ignore_above: 1024 + overwrite: true + description: Referrer for this HTTP request. + + - name: response + type: group + fields: + + - name: status_code + type: long + description: > + The status code of the HTTP response. + overwrite: true + + - name: finished + type: boolean + description: > + Used by the Node agent to indicate when in the response life cycle an error has occurred. + overwrite: true + + - name: headers + type: object + enabled: false + description: > + The canonical headers of the monitored HTTP response. + + - name: labels + type: object + object_type_params: + - object_type: keyword + - object_type: boolean + - object_type: scaled_float + scaling_factor: 1000000 + dynamic: true + overwrite: true + description: > + A flat mapping of user-defined labels with string, boolean or number values. + + - name: service + type: group + dynamic: false + description: > + Service fields. + fields: + - name: name + type: keyword + description: > + Immutable name of the service emitting this event. + overwrite: true + + - name: version + type: keyword + description: > + Version of the service emitting this event. + overwrite: true + + - name: environment + type: keyword + description: > + Service environment. + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Unique meaningful name of the service node. + overwrite: true + + - name: language + type: group + fields: + + - name: name + type: keyword + description: > + Name of the programming language used. + + - name: version + type: keyword + description: > + Version of the programming language used. + + - name: runtime + type: group + fields: + + - name: name + type: keyword + description: > + Name of the runtime used. + + - name: version + type: keyword + description: > + Version of the runtime used. + + - name: framework + type: group + fields: + + - name: name + type: keyword + description: > + Name of the framework used. + + - name: version + type: keyword + description: > + Version of the framework used. + + - name: transaction + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The transaction ID. + - name: sampled + type: boolean + description: > + Transactions that are 'sampled' will include all available information. Transactions that are not sampled will not have spans or context. + - name: type + type: keyword + description: > + Keyword of specific relevance in the service's domain (eg. 'request', 'backgroundjob', etc) + - name: name + type: keyword + multi_fields: + - name: text + type: text + description: > + Generic designation of a transaction in the scope of a single service (eg. 'GET /users/:id'). + + - name: duration + type: group + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: self_time + type: group + description: > + Portion of the transaction's duration where no direct child was running + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: breakdown + type: group + description: > + Counter for collected breakdowns for the transaction + fields: + - name: count + type: long + + - name: trace + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The ID of the trace to which the event belongs to. + + - name: parent + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The ID of the parent event. + + - name: agent + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + Name of the agent used. + overwrite: true + + - name: version + type: keyword + description: > + Version of the agent used. + overwrite: true + + - name: ephemeral_id + type: keyword + description: > + The Ephemeral ID identifies a running process. + overwrite: true + + - name: container + type: group + dynamic: false + title: Container + description: > + Container fields are used for meta information about the specific container + that is the source of information. These fields help correlate data based + containers from any runtime. + fields: + + - name: id + type: keyword + description: > + Unique container id. + overwrite: true + + - name: kubernetes + type: group + dynamic: false + title: Kubernetes + description: > + Kubernetes metadata reported by agents + fields: + + - name: namespace + type: keyword + description: > + Kubernetes namespace + overwrite: true + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Kubernetes node name + overwrite: true + + - name: pod + type: group + fields: + + - name: name + type: keyword + description: > + Kubernetes pod name + overwrite: true + + - name: uid + type: keyword + description: > + Kubernetes Pod UID + overwrite: true + + - name: host + type: group + dynamic: false + description: > + Optional host fields. + fields: + + - name: architecture + type: keyword + description: > + The architecture of the host the event was recorded on. + overwrite: true + + - name: hostname + type: keyword + description: > + The hostname of the host the event was recorded on. + overwrite: true + + - name: name + type: keyword + description: > + Name of the host the event was recorded on. + It can contain same information as host.hostname or a name specified by the user. + overwrite: true + + - name: ip + type: ip + description: > + IP of the host that records the event. + overwrite: true + + - name: os + title: Operating System + group: 2 + description: > + The OS fields contain information about the operating system. + type: group + fields: + - name: platform + type: keyword + description: > + The platform of the host the event was recorded on. + overwrite: true + + - name: process + type: group + dynamic: false + description: > + Information pertaining to the running process where the data was collected + fields: + - name: args + level: extended + type: keyword + description: > + Process arguments. + + May be filtered to protect sensitive information. + overwrite: true + + - name: pid + type: long + description: > + Numeric process ID of the service process. + overwrite: true + + - name: ppid + type: long + description: > + Numeric ID of the service's parent process. + overwrite: true + + - name: title + type: keyword + description: > + Service process title. + overwrite: true + + - name: observer + type: group + dynamic: false + fields: + + - name: listening + type: keyword + description: > + Address the server is listening on. + + - name: hostname + type: keyword + overwrite: true + description: > + Hostname of the APM Server. + + - name: version + type: keyword + overwrite: true + description: > + APM Server version. + + - name: version_major + type: byte + description: > + Major version number of the observer + + - name: type + type: keyword + overwrite: true + description: > + The type will be set to `apm-server`. + + - name: user + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + The username of the logged in user. + overwrite: true + + - name: id + type: keyword + description: > + Identifier of the logged in user. + overwrite: true + + - name: email + type: keyword + description: > + Email of the logged in user. + overwrite: true + + - name: client + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the client of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: source + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the source of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: destination + title: Destination + group: 2 + description: 'Destination fields describe details about the destination of a packet/event. + + Destination fields are usually populated in conjunction with source fields.' + type: group + fields: + - name: address + level: extended + type: keyword + ignore_above: 1024 + description: 'Some event destination addresses are defined ambiguously. The + event will sometimes list an IP, a domain or a unix socket. You should always + store the raw address in the `.address` field. + + Then it should be duplicated to `.ip` or `.domain`, depending on which one + it is.' + overwrite: true + + - name: ip + level: core + type: ip + description: 'IP addess of the destination. + + Can be one of multiple IPv4 or IPv6 addresses.' + overwrite: true + + - name: port + level: core + type: long + format: string + description: Port of the destination. + overwrite: true + + - name: user_agent + dynamic: false + title: User agent + description: > + The user_agent fields normally come from a browser request. They often + show up in web service logs coming from the parsed user agent string. + type: group + overwrite: true + fields: + + - name: original + type: keyword + description: > + Unparsed version of the user_agent. + example: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1" + overwrite: true + + multi_fields: + - name: text + type: text + description: > + Software agent acting in behalf of a user, eg. a web browser / OS combination. + overwrite: true + + - name: name + type: keyword + overwrite: true + example: Safari + description: > + Name of the user agent. + + - name: version + type: keyword + overwrite: true + description: > + Version of the user agent. + example: 12.0 + + - name: device + type: group + overwrite: true + title: Device + description: > + Information concerning the device. + fields: + + - name: name + type: keyword + overwrite: true + example: iPhone + description: > + Name of the device. + + - name: os + type: group + overwrite: true + title: Operating System + description: > + The OS fields contain information about the operating system. + fields: + + - name: platform + type: keyword + overwrite: true + description: > + Operating system platform (such centos, ubuntu, windows). + example: darwin + + - name: name + type: keyword + overwrite: true + example: "Mac OS X" + description: > + Operating system name, without the version. + + - name: full + type: keyword + overwrite: true + example: "Mac OS Mojave" + description: > + Operating system name, including the version or code name. + + - name: family + type: keyword + overwrite: true + example: "debian" + description: > + OS family (such as redhat, debian, freebsd, windows). + + - name: version + type: keyword + overwrite: true + example: "10.14.1" + description: > + Operating system version as a raw string. + + - name: kernel + type: keyword + overwrite: true + example: "4.4.0-112-generic" + description: > + Operating system kernel version as a raw string. + + - name: experimental + type: object + dynamic: true + description: Additional experimental data sent by the agents. + + - name: cloud + title: Cloud + group: 2 + type: group + description: > + Cloud metadata reported by agents + fields: + - name: account + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account name + overwrite: true + - name: availability_zone + level: extended + type: keyword + ignore_above: 1024 + description: Cloud availability zone name + example: us-east1-a + overwrite: true + - name: instance + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine name + overwrite: true + - name: machine + type: group + dynamic: false + fields: + - name: type + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine type + example: t2.medium + overwrite: true + - name: project + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project name + overwrite: true + - name: provider + level: extended + type: keyword + ignore_above: 1024 + description: Cloud provider name + example: gcp + overwrite: true + - name: region + level: extended + type: keyword + ignore_above: 1024 + description: Cloud region name + example: us-east1 + overwrite: true + - name: error type: group description: > diff --git a/model/metricset/_meta/fields.yml b/model/metricset/_meta/fields.yml index ddd4d789b17..dc8396d5667 100644 --- a/model/metricset/_meta/fields.yml +++ b/model/metricset/_meta/fields.yml @@ -1,3 +1,683 @@ +- key: apm-transaction-metrics + title: "APM Transaction Metrics" + description: > + APM transaction metrics, and transaction metrics-specific properties, + such as transaction.root. + short_config: true + fields: + - name: processor.name + type: keyword + description: Processor name. + + - name: processor.event + type: keyword + description: Processor event. + + - name: timestamp + type: group + fields: + - name: us + type: long + count: 1 + description: > + Timestamp of the event in microseconds since Unix epoch. + + - name: labels + type: object + object_type_params: + - object_type: keyword + - object_type: boolean + - object_type: scaled_float + scaling_factor: 1000000 + dynamic: true + overwrite: true + description: > + A flat mapping of user-defined labels with string, boolean or number values. + + - name: service + type: group + dynamic: false + description: > + Service fields. + fields: + - name: name + type: keyword + description: > + Immutable name of the service emitting this event. + overwrite: true + + - name: version + type: keyword + description: > + Version of the service emitting this event. + overwrite: true + + - name: environment + type: keyword + description: > + Service environment. + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Unique meaningful name of the service node. + overwrite: true + + - name: language + type: group + fields: + + - name: name + type: keyword + description: > + Name of the programming language used. + + - name: version + type: keyword + description: > + Version of the programming language used. + + - name: runtime + type: group + fields: + + - name: name + type: keyword + description: > + Name of the runtime used. + + - name: version + type: keyword + description: > + Version of the runtime used. + + - name: framework + type: group + fields: + + - name: name + type: keyword + description: > + Name of the framework used. + + - name: version + type: keyword + description: > + Version of the framework used. + + - name: transaction + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The transaction ID. + - name: sampled + type: boolean + description: > + Transactions that are 'sampled' will include all available information. Transactions that are not sampled will not have spans or context. + - name: type + type: keyword + description: > + Keyword of specific relevance in the service's domain (eg. 'request', 'backgroundjob', etc) + - name: name + type: keyword + multi_fields: + - name: text + type: text + description: > + Generic designation of a transaction in the scope of a single service (eg. 'GET /users/:id'). + + - name: duration + type: group + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: self_time + type: group + description: > + Portion of the transaction's duration where no direct child was running + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: breakdown + type: group + description: > + Counter for collected breakdowns for the transaction + fields: + - name: count + type: long + + - name: root + type: boolean + description: > + Identifies metrics for root transactions. This can be used for calculating metrics for traces. + + + - name: span + type: group + dynamic: false + fields: + - name: type + type: keyword + count: 1 + description: > + Keyword of specific relevance in the service's domain (eg: 'db.postgresql.query', 'template.erb', 'cache', etc). + + - name: subtype + type: keyword + count: 1 + description: > + A further sub-division of the type (e.g. postgresql, elasticsearch) + + - name: self_time + type: group + description: > + Portion of the span's duration where no direct child was running + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: agent + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + Name of the agent used. + overwrite: true + + - name: version + type: keyword + description: > + Version of the agent used. + overwrite: true + + - name: ephemeral_id + type: keyword + description: > + The Ephemeral ID identifies a running process. + overwrite: true + + - name: container + type: group + dynamic: false + title: Container + description: > + Container fields are used for meta information about the specific container + that is the source of information. These fields help correlate data based + containers from any runtime. + fields: + + - name: id + type: keyword + description: > + Unique container id. + overwrite: true + + - name: kubernetes + type: group + dynamic: false + title: Kubernetes + description: > + Kubernetes metadata reported by agents + fields: + + - name: namespace + type: keyword + description: > + Kubernetes namespace + overwrite: true + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Kubernetes node name + overwrite: true + + - name: pod + type: group + fields: + + - name: name + type: keyword + description: > + Kubernetes pod name + overwrite: true + + - name: uid + type: keyword + description: > + Kubernetes Pod UID + overwrite: true + + - name: host + type: group + dynamic: false + description: > + Optional host fields. + fields: + + - name: architecture + type: keyword + description: > + The architecture of the host the event was recorded on. + overwrite: true + + - name: hostname + type: keyword + description: > + The hostname of the host the event was recorded on. + overwrite: true + + - name: name + type: keyword + description: > + Name of the host the event was recorded on. + It can contain same information as host.hostname or a name specified by the user. + overwrite: true + + - name: ip + type: ip + description: > + IP of the host that records the event. + overwrite: true + + - name: os + title: Operating System + group: 2 + description: > + The OS fields contain information about the operating system. + type: group + fields: + - name: platform + type: keyword + description: > + The platform of the host the event was recorded on. + overwrite: true + + - name: process + type: group + dynamic: false + description: > + Information pertaining to the running process where the data was collected + fields: + - name: args + level: extended + type: keyword + description: > + Process arguments. + + May be filtered to protect sensitive information. + overwrite: true + + - name: pid + type: long + description: > + Numeric process ID of the service process. + overwrite: true + + - name: ppid + type: long + description: > + Numeric ID of the service's parent process. + overwrite: true + + - name: title + type: keyword + description: > + Service process title. + overwrite: true + + - name: observer + type: group + dynamic: false + fields: + + - name: listening + type: keyword + description: > + Address the server is listening on. + + - name: hostname + type: keyword + overwrite: true + description: > + Hostname of the APM Server. + + - name: version + type: keyword + overwrite: true + description: > + APM Server version. + + - name: version_major + type: byte + description: > + Major version number of the observer + + - name: type + type: keyword + overwrite: true + description: > + The type will be set to `apm-server`. + + - name: user + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + The username of the logged in user. + overwrite: true + + - name: id + type: keyword + description: > + Identifier of the logged in user. + overwrite: true + + - name: email + type: keyword + description: > + Email of the logged in user. + overwrite: true + + - name: client + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the client of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: source + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the source of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: destination + title: Destination + group: 2 + description: 'Destination fields describe details about the destination of a packet/event. + + Destination fields are usually populated in conjunction with source fields.' + type: group + fields: + - name: address + level: extended + type: keyword + ignore_above: 1024 + description: 'Some event destination addresses are defined ambiguously. The + event will sometimes list an IP, a domain or a unix socket. You should always + store the raw address in the `.address` field. + + Then it should be duplicated to `.ip` or `.domain`, depending on which one + it is.' + overwrite: true + + - name: ip + level: core + type: ip + description: 'IP addess of the destination. + + Can be one of multiple IPv4 or IPv6 addresses.' + overwrite: true + + - name: port + level: core + type: long + format: string + description: Port of the destination. + overwrite: true + + - name: user_agent + dynamic: false + title: User agent + description: > + The user_agent fields normally come from a browser request. They often + show up in web service logs coming from the parsed user agent string. + type: group + overwrite: true + fields: + + - name: original + type: keyword + description: > + Unparsed version of the user_agent. + example: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1" + overwrite: true + + multi_fields: + - name: text + type: text + description: > + Software agent acting in behalf of a user, eg. a web browser / OS combination. + overwrite: true + + - name: name + type: keyword + overwrite: true + example: Safari + description: > + Name of the user agent. + + - name: version + type: keyword + overwrite: true + description: > + Version of the user agent. + example: 12.0 + + - name: device + type: group + overwrite: true + title: Device + description: > + Information concerning the device. + fields: + + - name: name + type: keyword + overwrite: true + example: iPhone + description: > + Name of the device. + + - name: os + type: group + overwrite: true + title: Operating System + description: > + The OS fields contain information about the operating system. + fields: + + - name: platform + type: keyword + overwrite: true + description: > + Operating system platform (such centos, ubuntu, windows). + example: darwin + + - name: name + type: keyword + overwrite: true + example: "Mac OS X" + description: > + Operating system name, without the version. + + - name: full + type: keyword + overwrite: true + example: "Mac OS Mojave" + description: > + Operating system name, including the version or code name. + + - name: family + type: keyword + overwrite: true + example: "debian" + description: > + OS family (such as redhat, debian, freebsd, windows). + + - name: version + type: keyword + overwrite: true + example: "10.14.1" + description: > + Operating system version as a raw string. + + - name: kernel + type: keyword + overwrite: true + example: "4.4.0-112-generic" + description: > + Operating system kernel version as a raw string. + + - name: experimental + type: object + dynamic: true + description: Additional experimental data sent by the agents. + + - name: cloud + title: Cloud + group: 2 + type: group + description: > + Cloud metadata reported by agents + fields: + - name: account + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account name + overwrite: true + - name: availability_zone + level: extended + type: keyword + ignore_above: 1024 + description: Cloud availability zone name + example: us-east1-a + overwrite: true + - name: instance + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine name + overwrite: true + - name: machine + type: group + dynamic: false + fields: + - name: type + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine type + example: t2.medium + overwrite: true + - name: project + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project name + overwrite: true + - name: provider + level: extended + type: keyword + ignore_above: 1024 + description: Cloud provider name + example: gcp + overwrite: true + - name: region + level: extended + type: keyword + ignore_above: 1024 + description: Cloud region name + example: us-east1 + overwrite: true + + - name: event + type: group + fields: + + - name: outcome + level: core + type: keyword + ignore_above: 1024 + description: > + `event.outcome` simply denotes whether the event represents a success or a + failure from the perspective of the entity that produced the event. + example: success + overwrite: true + - key: system title: "System Metrics" description: > @@ -94,20 +774,3 @@ type: long format: bytes description: Memory usage by the current cgroup slice. - -- key: apm-transaction-metrics - title: "APM Transaction Metrics" - description: > - APM transaction metrics, and transaction metrics-specific properties, - such as transaction.root. - short_config: true - fields: - - name: transaction - type: group - dynamic: false - fields: - - - name: root - type: boolean - description: > - Identifies metrics for root transactions. This can be used for calculating metrics for traces. diff --git a/model/modeldecoder/generator/jsonschema.go b/model/modeldecoder/generator/jsonschema.go index 16f7ae7714f..65e25ea8aa2 100644 --- a/model/modeldecoder/generator/jsonschema.go +++ b/model/modeldecoder/generator/jsonschema.go @@ -121,10 +121,6 @@ func (g *JSONSchemaGenerator) generate(st structType, key string, prop *property default: switch t := f.Type().Underlying().(type) { case *types.Map: - if _, ok := tags[tagPatternKeys]; !ok && name == "" { - // ignore the field in case no json name and no patternProperties are given - continue - } nestedProp := property{Properties: make(map[string]*property)} if err = generateJSONPropertyMap(&info, prop, &childProp, &nestedProp); err != nil { break @@ -240,7 +236,7 @@ type property struct { Type *propertyType `json:"type,omitempty"` // AdditionalProperties should default to `true` and be set to `false` // in case PatternProperties are set - AdditionalProperties *bool `json:"additionalProperties,omitempty"` + AdditionalProperties interface{} `json:"additionalProperties,omitempty"` PatternProperties map[string]*property `json:"patternProperties,omitempty"` Properties map[string]*property `json:"properties,omitempty"` Items *property `json:"items,omitempty"` diff --git a/model/modeldecoder/generator/jsonschema_test.go b/model/modeldecoder/generator/jsonschema_test.go index 448c39dac0b..d35a1801c67 100644 --- a/model/modeldecoder/generator/jsonschema_test.go +++ b/model/modeldecoder/generator/jsonschema_test.go @@ -23,10 +23,11 @@ import ( "reflect" "testing" - "github.com/elastic/apm-server/model/modeldecoder/generator/generatortest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/xeipuuv/gojsonschema" + + "github.com/elastic/apm-server/model/modeldecoder/generator/generatortest" ) type testcase struct { diff --git a/model/modeldecoder/generator/map.go b/model/modeldecoder/generator/map.go index ab417ed8709..40bc9616ef3 100644 --- a/model/modeldecoder/generator/map.go +++ b/model/modeldecoder/generator/map.go @@ -159,19 +159,23 @@ func generateJSONPropertyMap(info *fieldInfo, parent *property, child *property, child.Type.add(TypeNameObject) patternName, isPatternProp := info.tags[tagPatternKeys] delete(info.tags, tagPatternKeys) - if !isPatternProp && name == "" { - // the object (map) can be places as a property with a defined key, - // or as a patternProperty with a defined key pattern - // if both are missing the field cannot be added - return fmt.Errorf("invalid combination: either json name or tag %s must be given", tagPatternKeys) - } - if !isPatternProp { - // if no pattern property is given, the child map will be nested directly as - // property inside the parent property, identified by it's json name - // e.g. {"parent":{"properties":{"jsonNameXY":{..}}}} + + nestedParent := child + if name == "" { + // The map does not have a json name defined, in which case it is nested directly + // inside the parent object's patternProperties/additionalProperties + // e.g. {"parent":{"patternProperties":{"patternXY":{..}}}} *nested = *child - parent.Properties[name] = nested + nestedParent = parent + } else { + // The map does have a json name defined, in which case it is nested as + // patternProperties/additionalProperties inside an object, which itself is nested + // inside the parent property, identified by its json name + // e.g. {"parent":{"properties":{"jsonNameXY":{"patternProperties":{"patternXY":{..}}}}}} + parent.Properties[name] = child } + + haveValueSchema := len(info.tags) > 0 if maxLen, ok := info.tags[tagMaxLengthVals]; ok { nested.MaxLength = json.Number(maxLen) delete(info.tags, tagMaxLengthVals) @@ -183,42 +187,30 @@ func generateJSONPropertyMap(info *fieldInfo, parent *property, child *property, } delete(info.tags, tagInputTypesVals) nested.Type = &propertyType{names: names} - } - if !isPatternProp { - // nothing more to do when no key pattern is given - return nil - } - pattern, ok := info.parsed.patternVariables[patternName] - if !ok { - return fmt.Errorf("unhandled %s tag value %s", tagPatternKeys, pattern) - } - // for map key patterns two options are supported: - // - the map does not have a json name defined, in which case it is nested directly - // inside the parent object's patternProperty - // e.g. {"parent":{"patternProperties":{"patternXY":{..}}}} - // - the map does have a json name defined, in which case it is nested as - // patternProperty inside an object, which itself is nested - // inside the parent property, identified by it's json name - // e.g. {"parent":{"properties":{"jsonNameXY":{"patternProperties":{"patternXY":{..}}}}}} - if name == "" { - if parent.PatternProperties == nil { - parent.PatternProperties = make(map[string]*property) - } + } else { valueType := info.field.Type().Underlying().(*types.Map).Elem() - typeName, ok := propertyTypes[valueType.String()] - if !ok { - typeName = TypeNameObject + if !types.IsInterface(valueType) { + haveValueSchema = true + typeName, ok := propertyTypes[valueType.String()] + if !ok { + typeName = TypeNameObject + } + nested.Type = &propertyType{names: []propertyTypeName{typeName}} } - nested.Type = &propertyType{names: []propertyTypeName{typeName}} - parent.PatternProperties[pattern] = nested - parent.AdditionalProperties = new(bool) - return nil } - if child.PatternProperties == nil { - child.PatternProperties = make(map[string]*property) + + if isPatternProp { + pattern, ok := info.parsed.patternVariables[patternName] + if !ok { + return fmt.Errorf("unhandled %s tag value %s", tagPatternKeys, pattern) + } + if nestedParent.PatternProperties == nil { + nestedParent.PatternProperties = make(map[string]*property) + } + nestedParent.PatternProperties[pattern] = nested + nestedParent.AdditionalProperties = false + } else if haveValueSchema { + nestedParent.AdditionalProperties = nested } - child.PatternProperties[pattern] = nested - child.AdditionalProperties = new(bool) - parent.Properties[name] = child return nil } diff --git a/model/profile/_meta/fields.yml b/model/profile/_meta/fields.yml index 4821e008654..fc3fc7adaba 100644 --- a/model/profile/_meta/fields.yml +++ b/model/profile/_meta/fields.yml @@ -2,6 +2,574 @@ title: APM Profile description: Profiling-specific data for APM. fields: + - name: processor.name + type: keyword + description: Processor name. + + - name: processor.event + type: keyword + description: Processor event. + + - name: timestamp + type: group + fields: + - name: us + type: long + count: 1 + description: > + Timestamp of the event in microseconds since Unix epoch. + + - name: labels + type: object + object_type_params: + - object_type: keyword + - object_type: boolean + - object_type: scaled_float + scaling_factor: 1000000 + dynamic: true + overwrite: true + description: > + A flat mapping of user-defined labels with string, boolean or number values. + + - name: service + type: group + dynamic: false + description: > + Service fields. + fields: + - name: name + type: keyword + description: > + Immutable name of the service emitting this event. + overwrite: true + + - name: version + type: keyword + description: > + Version of the service emitting this event. + overwrite: true + + - name: environment + type: keyword + description: > + Service environment. + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Unique meaningful name of the service node. + overwrite: true + + - name: language + type: group + fields: + + - name: name + type: keyword + description: > + Name of the programming language used. + + - name: version + type: keyword + description: > + Version of the programming language used. + + - name: runtime + type: group + fields: + + - name: name + type: keyword + description: > + Name of the runtime used. + + - name: version + type: keyword + description: > + Version of the runtime used. + + - name: framework + type: group + fields: + + - name: name + type: keyword + description: > + Name of the framework used. + + - name: version + type: keyword + description: > + Version of the framework used. + + - name: agent + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + Name of the agent used. + overwrite: true + + - name: version + type: keyword + description: > + Version of the agent used. + overwrite: true + + - name: ephemeral_id + type: keyword + description: > + The Ephemeral ID identifies a running process. + overwrite: true + + - name: container + type: group + dynamic: false + title: Container + description: > + Container fields are used for meta information about the specific container + that is the source of information. These fields help correlate data based + containers from any runtime. + fields: + + - name: id + type: keyword + description: > + Unique container id. + overwrite: true + + - name: kubernetes + type: group + dynamic: false + title: Kubernetes + description: > + Kubernetes metadata reported by agents + fields: + + - name: namespace + type: keyword + description: > + Kubernetes namespace + overwrite: true + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Kubernetes node name + overwrite: true + + - name: pod + type: group + fields: + + - name: name + type: keyword + description: > + Kubernetes pod name + overwrite: true + + - name: uid + type: keyword + description: > + Kubernetes Pod UID + overwrite: true + + - name: host + type: group + dynamic: false + description: > + Optional host fields. + fields: + + - name: architecture + type: keyword + description: > + The architecture of the host the event was recorded on. + overwrite: true + + - name: hostname + type: keyword + description: > + The hostname of the host the event was recorded on. + overwrite: true + + - name: name + type: keyword + description: > + Name of the host the event was recorded on. + It can contain same information as host.hostname or a name specified by the user. + overwrite: true + + - name: ip + type: ip + description: > + IP of the host that records the event. + overwrite: true + + - name: os + title: Operating System + group: 2 + description: > + The OS fields contain information about the operating system. + type: group + fields: + - name: platform + type: keyword + description: > + The platform of the host the event was recorded on. + overwrite: true + + - name: process + type: group + dynamic: false + description: > + Information pertaining to the running process where the data was collected + fields: + - name: args + level: extended + type: keyword + description: > + Process arguments. + + May be filtered to protect sensitive information. + overwrite: true + + - name: pid + type: long + description: > + Numeric process ID of the service process. + overwrite: true + + - name: ppid + type: long + description: > + Numeric ID of the service's parent process. + overwrite: true + + - name: title + type: keyword + description: > + Service process title. + overwrite: true + + - name: observer + type: group + dynamic: false + fields: + + - name: listening + type: keyword + description: > + Address the server is listening on. + + - name: hostname + type: keyword + overwrite: true + description: > + Hostname of the APM Server. + + - name: version + type: keyword + overwrite: true + description: > + APM Server version. + + - name: version_major + type: byte + description: > + Major version number of the observer + + - name: type + type: keyword + overwrite: true + description: > + The type will be set to `apm-server`. + + - name: user + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + The username of the logged in user. + overwrite: true + + - name: id + type: keyword + description: > + Identifier of the logged in user. + overwrite: true + + - name: email + type: keyword + description: > + Email of the logged in user. + overwrite: true + + - name: client + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the client of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: source + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the source of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: destination + title: Destination + group: 2 + description: 'Destination fields describe details about the destination of a packet/event. + + Destination fields are usually populated in conjunction with source fields.' + type: group + fields: + - name: address + level: extended + type: keyword + ignore_above: 1024 + description: 'Some event destination addresses are defined ambiguously. The + event will sometimes list an IP, a domain or a unix socket. You should always + store the raw address in the `.address` field. + + Then it should be duplicated to `.ip` or `.domain`, depending on which one + it is.' + overwrite: true + + - name: ip + level: core + type: ip + description: 'IP addess of the destination. + + Can be one of multiple IPv4 or IPv6 addresses.' + overwrite: true + + - name: port + level: core + type: long + format: string + description: Port of the destination. + overwrite: true + + - name: user_agent + dynamic: false + title: User agent + description: > + The user_agent fields normally come from a browser request. They often + show up in web service logs coming from the parsed user agent string. + type: group + overwrite: true + fields: + + - name: original + type: keyword + description: > + Unparsed version of the user_agent. + example: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1" + overwrite: true + + multi_fields: + - name: text + type: text + description: > + Software agent acting in behalf of a user, eg. a web browser / OS combination. + overwrite: true + + - name: name + type: keyword + overwrite: true + example: Safari + description: > + Name of the user agent. + + - name: version + type: keyword + overwrite: true + description: > + Version of the user agent. + example: 12.0 + + - name: device + type: group + overwrite: true + title: Device + description: > + Information concerning the device. + fields: + + - name: name + type: keyword + overwrite: true + example: iPhone + description: > + Name of the device. + + - name: os + type: group + overwrite: true + title: Operating System + description: > + The OS fields contain information about the operating system. + fields: + + - name: platform + type: keyword + overwrite: true + description: > + Operating system platform (such centos, ubuntu, windows). + example: darwin + + - name: name + type: keyword + overwrite: true + example: "Mac OS X" + description: > + Operating system name, without the version. + + - name: full + type: keyword + overwrite: true + example: "Mac OS Mojave" + description: > + Operating system name, including the version or code name. + + - name: family + type: keyword + overwrite: true + example: "debian" + description: > + OS family (such as redhat, debian, freebsd, windows). + + - name: version + type: keyword + overwrite: true + example: "10.14.1" + description: > + Operating system version as a raw string. + + - name: kernel + type: keyword + overwrite: true + example: "4.4.0-112-generic" + description: > + Operating system kernel version as a raw string. + + - name: experimental + type: object + dynamic: true + description: Additional experimental data sent by the agents. + + - name: cloud + title: Cloud + group: 2 + type: group + description: > + Cloud metadata reported by agents + fields: + - name: account + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account name + overwrite: true + - name: availability_zone + level: extended + type: keyword + ignore_above: 1024 + description: Cloud availability zone name + example: us-east1-a + overwrite: true + - name: instance + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine name + overwrite: true + - name: machine + type: group + dynamic: false + fields: + - name: type + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine type + example: t2.medium + overwrite: true + - name: project + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project name + overwrite: true + - name: provider + level: extended + type: keyword + ignore_above: 1024 + description: Cloud provider name + example: gcp + overwrite: true + - name: region + level: extended + type: keyword + ignore_above: 1024 + description: Cloud region name + example: us-east1 + overwrite: true + - name: profile type: group dynamic: false diff --git a/model/span/_meta/fields.yml b/model/span/_meta/fields.yml index 9e460c9f569..be958fe1fe7 100644 --- a/model/span/_meta/fields.yml +++ b/model/span/_meta/fields.yml @@ -2,6 +2,691 @@ title: APM Span description: Span-specific data for APM. fields: + - name: processor.name + type: keyword + description: Processor name. + + - name: processor.event + type: keyword + description: Processor event. + + - name: timestamp + type: group + fields: + - name: us + type: long + count: 1 + description: > + Timestamp of the event in microseconds since Unix epoch. + + - name: labels + type: object + object_type_params: + - object_type: keyword + - object_type: boolean + - object_type: scaled_float + scaling_factor: 1000000 + dynamic: true + overwrite: true + description: > + A flat mapping of user-defined labels with string, boolean or number values. + + - name: service + type: group + dynamic: false + description: > + Service fields. + fields: + - name: name + type: keyword + description: > + Immutable name of the service emitting this event. + overwrite: true + + - name: version + type: keyword + description: > + Version of the service emitting this event. + overwrite: true + + - name: environment + type: keyword + description: > + Service environment. + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Unique meaningful name of the service node. + overwrite: true + + - name: language + type: group + fields: + + - name: name + type: keyword + description: > + Name of the programming language used. + + - name: version + type: keyword + description: > + Version of the programming language used. + + - name: runtime + type: group + fields: + + - name: name + type: keyword + description: > + Name of the runtime used. + + - name: version + type: keyword + description: > + Version of the runtime used. + + - name: framework + type: group + fields: + + - name: name + type: keyword + description: > + Name of the framework used. + + - name: version + type: keyword + description: > + Version of the framework used. + + - name: transaction + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The transaction ID. + - name: sampled + type: boolean + description: > + Transactions that are 'sampled' will include all available information. Transactions that are not sampled will not have spans or context. + - name: type + type: keyword + description: > + Keyword of specific relevance in the service's domain (eg. 'request', 'backgroundjob', etc) + - name: name + type: keyword + multi_fields: + - name: text + type: text + description: > + Generic designation of a transaction in the scope of a single service (eg. 'GET /users/:id'). + + - name: duration + type: group + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: self_time + type: group + description: > + Portion of the transaction's duration where no direct child was running + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: breakdown + type: group + description: > + Counter for collected breakdowns for the transaction + fields: + - name: count + type: long + + - name: span + type: group + dynamic: false + fields: + - name: type + type: keyword + count: 1 + description: > + Keyword of specific relevance in the service's domain (eg: 'db.postgresql.query', 'template.erb', 'cache', etc). + + - name: subtype + type: keyword + count: 1 + description: > + A further sub-division of the type (e.g. postgresql, elasticsearch) + + - name: self_time + type: group + description: > + Portion of the span's duration where no direct child was running + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: trace + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The ID of the trace to which the event belongs to. + + - name: parent + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The ID of the parent event. + + - name: agent + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + Name of the agent used. + overwrite: true + + - name: version + type: keyword + description: > + Version of the agent used. + overwrite: true + + - name: ephemeral_id + type: keyword + description: > + The Ephemeral ID identifies a running process. + overwrite: true + + - name: container + type: group + dynamic: false + title: Container + description: > + Container fields are used for meta information about the specific container + that is the source of information. These fields help correlate data based + containers from any runtime. + fields: + + - name: id + type: keyword + description: > + Unique container id. + overwrite: true + + - name: kubernetes + type: group + dynamic: false + title: Kubernetes + description: > + Kubernetes metadata reported by agents + fields: + + - name: namespace + type: keyword + description: > + Kubernetes namespace + overwrite: true + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Kubernetes node name + overwrite: true + + - name: pod + type: group + fields: + + - name: name + type: keyword + description: > + Kubernetes pod name + overwrite: true + + - name: uid + type: keyword + description: > + Kubernetes Pod UID + overwrite: true + + - name: host + type: group + dynamic: false + description: > + Optional host fields. + fields: + + - name: architecture + type: keyword + description: > + The architecture of the host the event was recorded on. + overwrite: true + + - name: hostname + type: keyword + description: > + The hostname of the host the event was recorded on. + overwrite: true + + - name: name + type: keyword + description: > + Name of the host the event was recorded on. + It can contain same information as host.hostname or a name specified by the user. + overwrite: true + + - name: ip + type: ip + description: > + IP of the host that records the event. + overwrite: true + + - name: os + title: Operating System + group: 2 + description: > + The OS fields contain information about the operating system. + type: group + fields: + - name: platform + type: keyword + description: > + The platform of the host the event was recorded on. + overwrite: true + + - name: process + type: group + dynamic: false + description: > + Information pertaining to the running process where the data was collected + fields: + - name: args + level: extended + type: keyword + description: > + Process arguments. + + May be filtered to protect sensitive information. + overwrite: true + + - name: pid + type: long + description: > + Numeric process ID of the service process. + overwrite: true + + - name: ppid + type: long + description: > + Numeric ID of the service's parent process. + overwrite: true + + - name: title + type: keyword + description: > + Service process title. + overwrite: true + + - name: observer + type: group + dynamic: false + fields: + + - name: listening + type: keyword + description: > + Address the server is listening on. + + - name: hostname + type: keyword + overwrite: true + description: > + Hostname of the APM Server. + + - name: version + type: keyword + overwrite: true + description: > + APM Server version. + + - name: version_major + type: byte + description: > + Major version number of the observer + + - name: type + type: keyword + overwrite: true + description: > + The type will be set to `apm-server`. + + - name: user + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + The username of the logged in user. + overwrite: true + + - name: id + type: keyword + description: > + Identifier of the logged in user. + overwrite: true + + - name: email + type: keyword + description: > + Email of the logged in user. + overwrite: true + + - name: client + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the client of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: source + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the source of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: destination + title: Destination + group: 2 + description: 'Destination fields describe details about the destination of a packet/event. + + Destination fields are usually populated in conjunction with source fields.' + type: group + fields: + - name: address + level: extended + type: keyword + ignore_above: 1024 + description: 'Some event destination addresses are defined ambiguously. The + event will sometimes list an IP, a domain or a unix socket. You should always + store the raw address in the `.address` field. + + Then it should be duplicated to `.ip` or `.domain`, depending on which one + it is.' + overwrite: true + + - name: ip + level: core + type: ip + description: 'IP addess of the destination. + + Can be one of multiple IPv4 or IPv6 addresses.' + overwrite: true + + - name: port + level: core + type: long + format: string + description: Port of the destination. + overwrite: true + + - name: user_agent + dynamic: false + title: User agent + description: > + The user_agent fields normally come from a browser request. They often + show up in web service logs coming from the parsed user agent string. + type: group + overwrite: true + fields: + + - name: original + type: keyword + description: > + Unparsed version of the user_agent. + example: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1" + overwrite: true + + multi_fields: + - name: text + type: text + description: > + Software agent acting in behalf of a user, eg. a web browser / OS combination. + overwrite: true + + - name: name + type: keyword + overwrite: true + example: Safari + description: > + Name of the user agent. + + - name: version + type: keyword + overwrite: true + description: > + Version of the user agent. + example: 12.0 + + - name: device + type: group + overwrite: true + title: Device + description: > + Information concerning the device. + fields: + + - name: name + type: keyword + overwrite: true + example: iPhone + description: > + Name of the device. + + - name: os + type: group + overwrite: true + title: Operating System + description: > + The OS fields contain information about the operating system. + fields: + + - name: platform + type: keyword + overwrite: true + description: > + Operating system platform (such centos, ubuntu, windows). + example: darwin + + - name: name + type: keyword + overwrite: true + example: "Mac OS X" + description: > + Operating system name, without the version. + + - name: full + type: keyword + overwrite: true + example: "Mac OS Mojave" + description: > + Operating system name, including the version or code name. + + - name: family + type: keyword + overwrite: true + example: "debian" + description: > + OS family (such as redhat, debian, freebsd, windows). + + - name: version + type: keyword + overwrite: true + example: "10.14.1" + description: > + Operating system version as a raw string. + + - name: kernel + type: keyword + overwrite: true + example: "4.4.0-112-generic" + description: > + Operating system kernel version as a raw string. + + - name: experimental + type: object + dynamic: true + description: Additional experimental data sent by the agents. + + - name: cloud + title: Cloud + group: 2 + type: group + description: > + Cloud metadata reported by agents + fields: + - name: account + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account name + overwrite: true + - name: availability_zone + level: extended + type: keyword + ignore_above: 1024 + description: Cloud availability zone name + example: us-east1-a + overwrite: true + - name: instance + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine name + overwrite: true + - name: machine + type: group + dynamic: false + fields: + - name: type + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine type + example: t2.medium + overwrite: true + - name: project + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project name + overwrite: true + - name: provider + level: extended + type: keyword + ignore_above: 1024 + description: Cloud provider name + example: gcp + overwrite: true + - name: region + level: extended + type: keyword + ignore_above: 1024 + description: Cloud region name + example: us-east1 + overwrite: true + + - name: event + type: group + fields: + + - name: outcome + level: core + type: keyword + ignore_above: 1024 + description: > + `event.outcome` simply denotes whether the event represents a success or a + failure from the perspective of the entity that produced the event. + example: success + overwrite: true + - name: view spans format: url label_template: "View Spans" diff --git a/model/transaction/_meta/fields.yml b/model/transaction/_meta/fields.yml index ea5aed0f653..32d4181fe34 100644 --- a/model/transaction/_meta/fields.yml +++ b/model/transaction/_meta/fields.yml @@ -2,6 +2,795 @@ title: APM Transaction description: Transaction-specific data for APM fields: + - name: processor.name + type: keyword + description: Processor name. + + - name: processor.event + type: keyword + description: Processor event. + + - name: timestamp + type: group + fields: + - name: us + type: long + count: 1 + description: > + Timestamp of the event in microseconds since Unix epoch. + + - name: url + type: group + description: > + A complete Url, with scheme, host and path. + dynamic: false + fields: + + - name: scheme + type: keyword + description: > + The protocol of the request, e.g. "https:". + overwrite: true + + - name: full + type: keyword + description: > + The full, possibly agent-assembled URL of the request, e.g https://example.com:443/search?q=elasticsearch#top. + overwrite: true + + - name: domain + type: keyword + description: > + The hostname of the request, e.g. "example.com". + overwrite: true + + - name: port + type: long + description: > + The port of the request, e.g. 443. + overwrite: true + + - name: path + type: keyword + description: > + The path of the request, e.g. "/search". + overwrite: true + + - name: query + type: keyword + description: > + The query string of the request, e.g. "q=elasticsearch". + overwrite: true + + - name: fragment + type: keyword + description: > + A fragment specifying a location in a web page , e.g. "top". + overwrite: true + + - name: http + type: group + dynamic: false + fields: + + - name: version + type: keyword + description: > + The http version of the request leading to this event. + overwrite: true + + - name: request + type: group + fields: + + - name: method + type: keyword + description: > + The http method of the request leading to this event. + overwrite: true + + - name: headers + type: object + enabled: false + description: > + The canonical headers of the monitored HTTP request. + + - name: referrer + type: keyword + ignore_above: 1024 + overwrite: true + description: Referrer for this HTTP request. + + - name: response + type: group + fields: + + - name: status_code + type: long + description: > + The status code of the HTTP response. + overwrite: true + + - name: finished + type: boolean + description: > + Used by the Node agent to indicate when in the response life cycle an error has occurred. + overwrite: true + + - name: headers + type: object + enabled: false + description: > + The canonical headers of the monitored HTTP response. + + - name: labels + type: object + object_type_params: + - object_type: keyword + - object_type: boolean + - object_type: scaled_float + scaling_factor: 1000000 + dynamic: true + overwrite: true + description: > + A flat mapping of user-defined labels with string, boolean or number values. + + - name: service + type: group + dynamic: false + description: > + Service fields. + fields: + - name: name + type: keyword + description: > + Immutable name of the service emitting this event. + overwrite: true + + - name: version + type: keyword + description: > + Version of the service emitting this event. + overwrite: true + + - name: environment + type: keyword + description: > + Service environment. + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Unique meaningful name of the service node. + overwrite: true + + - name: language + type: group + fields: + + - name: name + type: keyword + description: > + Name of the programming language used. + + - name: version + type: keyword + description: > + Version of the programming language used. + + - name: runtime + type: group + fields: + + - name: name + type: keyword + description: > + Name of the runtime used. + + - name: version + type: keyword + description: > + Version of the runtime used. + + - name: framework + type: group + fields: + + - name: name + type: keyword + description: > + Name of the framework used. + + - name: version + type: keyword + description: > + Version of the framework used. + + - name: transaction + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The transaction ID. + - name: sampled + type: boolean + description: > + Transactions that are 'sampled' will include all available information. Transactions that are not sampled will not have spans or context. + - name: type + type: keyword + description: > + Keyword of specific relevance in the service's domain (eg. 'request', 'backgroundjob', etc) + - name: name + type: keyword + multi_fields: + - name: text + type: text + description: > + Generic designation of a transaction in the scope of a single service (eg. 'GET /users/:id'). + + - name: duration + type: group + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: self_time + type: group + description: > + Portion of the transaction's duration where no direct child was running + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: breakdown + type: group + description: > + Counter for collected breakdowns for the transaction + fields: + - name: count + type: long + + - name: span + type: group + dynamic: false + fields: + - name: type + type: keyword + count: 1 + description: > + Keyword of specific relevance in the service's domain (eg: 'db.postgresql.query', 'template.erb', 'cache', etc). + + - name: subtype + type: keyword + count: 1 + description: > + A further sub-division of the type (e.g. postgresql, elasticsearch) + + - name: self_time + type: group + description: > + Portion of the span's duration where no direct child was running + fields: + - name: count + type: long + - name: sum + type: group + fields: + - name: us + type: long + + - name: trace + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The ID of the trace to which the event belongs to. + + - name: parent + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + The ID of the parent event. + + - name: agent + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + Name of the agent used. + overwrite: true + + - name: version + type: keyword + description: > + Version of the agent used. + overwrite: true + + - name: ephemeral_id + type: keyword + description: > + The Ephemeral ID identifies a running process. + overwrite: true + + - name: container + type: group + dynamic: false + title: Container + description: > + Container fields are used for meta information about the specific container + that is the source of information. These fields help correlate data based + containers from any runtime. + fields: + + - name: id + type: keyword + description: > + Unique container id. + overwrite: true + + - name: kubernetes + type: group + dynamic: false + title: Kubernetes + description: > + Kubernetes metadata reported by agents + fields: + + - name: namespace + type: keyword + description: > + Kubernetes namespace + overwrite: true + + - name: node + type: group + fields: + - name: name + type: keyword + description: > + Kubernetes node name + overwrite: true + + - name: pod + type: group + fields: + + - name: name + type: keyword + description: > + Kubernetes pod name + overwrite: true + + - name: uid + type: keyword + description: > + Kubernetes Pod UID + overwrite: true + + - name: host + type: group + dynamic: false + description: > + Optional host fields. + fields: + + - name: architecture + type: keyword + description: > + The architecture of the host the event was recorded on. + overwrite: true + + - name: hostname + type: keyword + description: > + The hostname of the host the event was recorded on. + overwrite: true + + - name: name + type: keyword + description: > + Name of the host the event was recorded on. + It can contain same information as host.hostname or a name specified by the user. + overwrite: true + + - name: ip + type: ip + description: > + IP of the host that records the event. + overwrite: true + + - name: os + title: Operating System + group: 2 + description: > + The OS fields contain information about the operating system. + type: group + fields: + - name: platform + type: keyword + description: > + The platform of the host the event was recorded on. + overwrite: true + + - name: process + type: group + dynamic: false + description: > + Information pertaining to the running process where the data was collected + fields: + - name: args + level: extended + type: keyword + description: > + Process arguments. + + May be filtered to protect sensitive information. + overwrite: true + + - name: pid + type: long + description: > + Numeric process ID of the service process. + overwrite: true + + - name: ppid + type: long + description: > + Numeric ID of the service's parent process. + overwrite: true + + - name: title + type: keyword + description: > + Service process title. + overwrite: true + + - name: observer + type: group + dynamic: false + fields: + + - name: listening + type: keyword + description: > + Address the server is listening on. + + - name: hostname + type: keyword + overwrite: true + description: > + Hostname of the APM Server. + + - name: version + type: keyword + overwrite: true + description: > + APM Server version. + + - name: version_major + type: byte + description: > + Major version number of the observer + + - name: type + type: keyword + overwrite: true + description: > + The type will be set to `apm-server`. + + - name: user + type: group + dynamic: false + fields: + + - name: name + type: keyword + description: > + The username of the logged in user. + overwrite: true + + - name: id + type: keyword + description: > + Identifier of the logged in user. + overwrite: true + + - name: email + type: keyword + description: > + Email of the logged in user. + overwrite: true + + - name: client + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the client of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: source + dynamic: false + type: group + fields: + - name: ip + type: ip + description: > + IP address of the source of a recorded event. + This is typically obtained from a request's X-Forwarded-For or the X-Real-IP header or falls back to a given configuration for remote address. + overwrite: true + + - name: destination + title: Destination + group: 2 + description: 'Destination fields describe details about the destination of a packet/event. + + Destination fields are usually populated in conjunction with source fields.' + type: group + fields: + - name: address + level: extended + type: keyword + ignore_above: 1024 + description: 'Some event destination addresses are defined ambiguously. The + event will sometimes list an IP, a domain or a unix socket. You should always + store the raw address in the `.address` field. + + Then it should be duplicated to `.ip` or `.domain`, depending on which one + it is.' + overwrite: true + + - name: ip + level: core + type: ip + description: 'IP addess of the destination. + + Can be one of multiple IPv4 or IPv6 addresses.' + overwrite: true + + - name: port + level: core + type: long + format: string + description: Port of the destination. + overwrite: true + + - name: user_agent + dynamic: false + title: User agent + description: > + The user_agent fields normally come from a browser request. They often + show up in web service logs coming from the parsed user agent string. + type: group + overwrite: true + fields: + + - name: original + type: keyword + description: > + Unparsed version of the user_agent. + example: "Mozilla/5.0 (iPhone; CPU iPhone OS 12_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1" + overwrite: true + + multi_fields: + - name: text + type: text + description: > + Software agent acting in behalf of a user, eg. a web browser / OS combination. + overwrite: true + + - name: name + type: keyword + overwrite: true + example: Safari + description: > + Name of the user agent. + + - name: version + type: keyword + overwrite: true + description: > + Version of the user agent. + example: 12.0 + + - name: device + type: group + overwrite: true + title: Device + description: > + Information concerning the device. + fields: + + - name: name + type: keyword + overwrite: true + example: iPhone + description: > + Name of the device. + + - name: os + type: group + overwrite: true + title: Operating System + description: > + The OS fields contain information about the operating system. + fields: + + - name: platform + type: keyword + overwrite: true + description: > + Operating system platform (such centos, ubuntu, windows). + example: darwin + + - name: name + type: keyword + overwrite: true + example: "Mac OS X" + description: > + Operating system name, without the version. + + - name: full + type: keyword + overwrite: true + example: "Mac OS Mojave" + description: > + Operating system name, including the version or code name. + + - name: family + type: keyword + overwrite: true + example: "debian" + description: > + OS family (such as redhat, debian, freebsd, windows). + + - name: version + type: keyword + overwrite: true + example: "10.14.1" + description: > + Operating system version as a raw string. + + - name: kernel + type: keyword + overwrite: true + example: "4.4.0-112-generic" + description: > + Operating system kernel version as a raw string. + + - name: experimental + type: object + dynamic: true + description: Additional experimental data sent by the agents. + + - name: cloud + title: Cloud + group: 2 + type: group + description: > + Cloud metadata reported by agents + fields: + - name: account + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud account name + overwrite: true + - name: availability_zone + level: extended + type: keyword + ignore_above: 1024 + description: Cloud availability zone name + example: us-east1-a + overwrite: true + - name: instance + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine name + overwrite: true + - name: machine + type: group + dynamic: false + fields: + - name: type + level: extended + type: keyword + ignore_above: 1024 + description: Cloud instance/machine type + example: t2.medium + overwrite: true + - name: project + type: group + dynamic: false + fields: + - name: id + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project ID + overwrite: true + - name: name + level: extended + type: keyword + ignore_above: 1024 + description: Cloud project name + overwrite: true + - name: provider + level: extended + type: keyword + ignore_above: 1024 + description: Cloud provider name + example: gcp + overwrite: true + - name: region + level: extended + type: keyword + ignore_above: 1024 + description: Cloud region name + example: us-east1 + overwrite: true + + - name: event + type: group + fields: + + - name: outcome + level: core + type: keyword + ignore_above: 1024 + description: > + `event.outcome` simply denotes whether the event represents a success or a + failure from the perspective of the entity that produced the event. + example: success + overwrite: true + - name: transaction type: group dynamic: false diff --git a/processor/stream/package_tests/error_attrs_test.go b/processor/stream/package_tests/error_attrs_test.go index 5a9c7eb5b82..d9a7e1ee0ec 100644 --- a/processor/stream/package_tests/error_attrs_test.go +++ b/processor/stream/package_tests/error_attrs_test.go @@ -18,7 +18,6 @@ package package_tests import ( - "encoding/json" "testing" "github.com/elastic/apm-server/beater/config" @@ -34,7 +33,6 @@ func errorProcSetup() *tests.ProcessorSetup { FullPayloadPath: "../testdata/intake-v2/errors.ndjson", TemplatePaths: []string{ "../../../model/error/_meta/fields.yml", - "../../../_meta/fields.common.yml", }, SchemaPath: "../../../docs/spec/v2/error.json", } @@ -154,79 +152,3 @@ func TestErrorKeywordLimitationOnErrorAttributes(t *testing.T) { }, ) } - -func TestPayloadDataForError(t *testing.T) { - //// add test data for testing - //// * specific edge cases - //// * multiple allowed data types - //// * regex pattern, time formats - //// * length restrictions, other than keyword length restrictions - errorProcSetup().DataValidation(t, - []tests.SchemaTestData{ - {Key: "error", - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{false}}}}, - {Key: "error.exception.code", Valid: val{"success", ""}, - Invalid: []tests.Invalid{{Msg: `validation error`, Values: val{false}}}}, - {Key: "error.exception.attributes", Valid: val{map[string]interface{}{}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{123}}}}, - {Key: "error.timestamp", - Valid: val{json.Number("1496170422281000")}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{"1496170422281000"}}}}, - {Key: "error.log.stacktrace.post_context", - Valid: val{[]interface{}{}, []interface{}{"context"}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{[]interface{}{123}}}, - {Msg: `decode error`, Values: val{"test"}}}}, - {Key: "error.log.stacktrace.pre_context", - Valid: val{[]interface{}{}, []interface{}{"context"}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{[]interface{}{123}}}, - {Msg: `decode error`, Values: val{"test"}}}}, - {Key: "error.exception.stacktrace.post_context", - Valid: val{[]interface{}{}, []interface{}{"context"}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{[]interface{}{123}}}, - {Msg: `decode error`, Values: val{"test"}}}}, - {Key: "error.exception.stacktrace.pre_context", - Valid: val{[]interface{}{}, []interface{}{"context"}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{[]interface{}{123}}}, - {Msg: `decode error`, Values: val{"test"}}}}, - {Key: "error.context.custom", - Valid: val{obj{"whatever": obj{"comes": obj{"end": -45}}}, obj{"whatever": 123}}, - Invalid: []tests.Invalid{ - {Msg: `validation error`, Values: val{ - obj{"what.ever": 123}, obj{"what*ever": 123}, obj{"what\"ever": 123}}}, - {Msg: `decode error`, Values: val{"context"}}}}, - {Key: "error.context.request.body", Valid: val{tests.Str1025, obj{}}, - Invalid: []tests.Invalid{{Msg: `validation error`, Values: val{102}}}}, - {Key: "error.context.request.headers", Valid: val{ - obj{"User-Agent": "go-1.1"}, - obj{"foo-bar": "a,b"}, - obj{"foo": []interface{}{"a", "b"}}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{102, obj{"foo": obj{"bar": "a"}}}}}}, - {Key: "error.context.response.headers", Valid: val{ - obj{"User-Agent": "go-1.1"}, - obj{"foo-bar": "a,b"}, - obj{"foo": []interface{}{"a", "b"}}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{102, obj{"foo": obj{"bar": "a"}}}}}}, - {Key: "error.context.request.env", Valid: val{obj{}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{102, "a"}}}}, - {Key: "error.context.request.cookies", Valid: val{obj{}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{102, "a"}}}}, - {Key: "error.context.tags", - Valid: val{obj{tests.Str1024Special: tests.Str1024Special}, obj{tests.Str1024: 123.45}, obj{tests.Str1024: true}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{"tags"}}, - {Msg: `validation error`, Values: val{ - obj{"invalid": tests.Str1025}, - obj{tests.Str1024: obj{}}, - obj{"invali*d": "hello"}, - obj{"invali\"d": "hello"}, - obj{"invali.d": "hello"}}}}}, - {Key: "error.context.user.id", Valid: val{123, tests.Str1024Special}, - Invalid: []tests.Invalid{ - {Msg: `validation error`, Values: val{obj{}, tests.Str1025}}}}, - }) -} diff --git a/processor/stream/package_tests/metadata_attrs_test.go b/processor/stream/package_tests/metadata_attrs_test.go index de05c682361..96c812dae3d 100644 --- a/processor/stream/package_tests/metadata_attrs_test.go +++ b/processor/stream/package_tests/metadata_attrs_test.go @@ -73,7 +73,10 @@ func metadataProcSetup() *tests.ProcessorSetup { intakeTestProcessor{Processor: stream.Processor{MaxEventSize: lrSize}}}, SchemaPath: "../../../docs/spec/v2/metadata.json", TemplatePaths: []string{ - "../../../_meta/fields.common.yml", + // we use the fields.yml file of a type that includes all the metadata fields + // this was changed with the removal of fields.common.yml + // TODO: move metadata package tests into event specific tests when refactoring package tests + "../../../model/transaction/_meta/fields.yml", }, FullPayloadPath: "../testdata/intake-v2/metadata.ndjson", } @@ -174,16 +177,3 @@ func metadataRequiredKeys() *tests.Set { func TestAttrsPresenceInMetadata(t *testing.T) { metadataProcSetup().AttrsPresence(t, metadataRequiredKeys(), nil) } -func TestInvalidPayloadsForMetadata(t *testing.T) { - type val []interface{} - - payloadData := []tests.SchemaTestData{ - {Key: "metadata.service.name", - Valid: val{"m"}, - Invalid: []tests.Invalid{ - {Msg: "validation error", Values: val{tests.Str1024Special}}, - {Msg: "validation error", Values: val{""}}, - }, - }} - metadataProcSetup().DataValidation(t, payloadData) -} diff --git a/processor/stream/package_tests/metricset_attrs_test.go b/processor/stream/package_tests/metricset_attrs_test.go index ec2bcd10735..75b9ce56cb3 100644 --- a/processor/stream/package_tests/metricset_attrs_test.go +++ b/processor/stream/package_tests/metricset_attrs_test.go @@ -18,7 +18,6 @@ package package_tests import ( - "encoding/json" "testing" "github.com/elastic/apm-server/beater/config" @@ -34,7 +33,6 @@ func metricsetProcSetup() *tests.ProcessorSetup { FullPayloadPath: "../testdata/intake-v2/metricsets.ndjson", TemplatePaths: []string{ "../../../model/metricset/_meta/fields.yml", - "../../../_meta/fields.common.yml", }, SchemaPath: "../../../docs/spec/v2/metricset.json", } @@ -48,42 +46,3 @@ func TestAttributesPresenceInMetric(t *testing.T) { ) metricsetProcSetup().AttrsPresence(t, requiredKeys, nil) } - -func TestInvalidPayloads(t *testing.T) { - type obj = map[string]interface{} - type val = []interface{} - - validMetric := obj{"value": json.Number("1.0")} - payloadData := []tests.SchemaTestData{ - {Key: "metricset.timestamp", - Valid: val{json.Number("1496170422281000")}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{"1496170422281000"}}}}, - {Key: "metricset.tags", - Valid: val{obj{tests.Str1024Special: tests.Str1024Special}, obj{tests.Str1024: 123.45}, obj{tests.Str1024: true}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{"tags"}}, - {Msg: `validation error`, Values: val{obj{"invalid": tests.Str1025}, obj{tests.Str1024: obj{}}}}, - {Msg: `validation error`, Values: val{obj{"invali*d": "hello"}, obj{"invali\"d": "hello"}}}}, - }, - { - Key: "metricset.samples", - Valid: val{obj{"valid-metric": validMetric}}, - Invalid: []tests.Invalid{ - { - Msg: `validation error`, - Values: val{ - obj{"metric\"key\"_quotes": validMetric}, - obj{"metric-*-key-star": validMetric}, - }, - }, - { - Msg: `decode error`, - Values: val{ - obj{"string-value": obj{"value": "foo"}}, - }, - }, - }, - }, - } - metricsetProcSetup().DataValidation(t, payloadData) -} diff --git a/processor/stream/package_tests/span_attrs_test.go b/processor/stream/package_tests/span_attrs_test.go index 4eb0c252689..b705413c2fc 100644 --- a/processor/stream/package_tests/span_attrs_test.go +++ b/processor/stream/package_tests/span_attrs_test.go @@ -18,7 +18,6 @@ package package_tests import ( - "encoding/json" "testing" "github.com/elastic/apm-server/beater/config" @@ -35,7 +34,6 @@ func spanProcSetup() *tests.ProcessorSetup { SchemaPath: "../../../docs/spec/v2/span.json", TemplatePaths: []string{ "../../../model/span/_meta/fields.yml", - "../../../_meta/fields.common.yml", }, } } @@ -50,7 +48,6 @@ func spanPayloadAttrsNotInFields() *tests.Set { ) } -// fields in _meta/fields.common.yml that are shared between several data types, but not with spans func spanFieldsNotInPayloadAttrs() *tests.Set { return tests.Union( tests.NewSet( @@ -182,32 +179,3 @@ func TestKeywordLimitationOnSpanAttrs(t *testing.T) { }, ) } - -func TestPayloadDataForSpans(t *testing.T) { - // add test data for testing - // * specific edge cases - // * multiple allowed dataypes - // * regex pattern, time formats - // * length restrictions, other than keyword length restrictions - - spanProcSetup().DataValidation(t, - []tests.SchemaTestData{ - {Key: "span.context.tags", - Valid: val{obj{tests.Str1024Special: tests.Str1024Special}, obj{tests.Str1024: 123.45}, obj{tests.Str1024: true}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{"tags"}}, - {Msg: `validation error`, Values: val{ - obj{"invalid": tests.Str1025}, obj{tests.Str1024: obj{}}, - obj{"invali*d": "hello"}, obj{"invali\"d": "hello"}, obj{"invali.d": "hello"}}}}}, - {Key: "span.timestamp", - Valid: val{json.Number("1496170422281000")}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{"1496170422281000"}}}}, - {Key: "span.stacktrace.pre_context", - Valid: val{[]interface{}{}, []interface{}{"context"}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{[]interface{}{123}, "test"}}}}, - {Key: "span.stacktrace.post_context", - Valid: val{[]interface{}{}, []interface{}{"context"}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{[]interface{}{123, "test"}}}}}, - }) -} diff --git a/processor/stream/package_tests/transaction_attrs_test.go b/processor/stream/package_tests/transaction_attrs_test.go index 4da0d241ccb..f38ccda6a23 100644 --- a/processor/stream/package_tests/transaction_attrs_test.go +++ b/processor/stream/package_tests/transaction_attrs_test.go @@ -18,7 +18,6 @@ package package_tests import ( - "encoding/json" "testing" "github.com/elastic/apm-server/beater/config" @@ -35,7 +34,6 @@ func transactionProcSetup() *tests.ProcessorSetup { SchemaPath: "../../../docs/spec/v2/transaction.json", TemplatePaths: []string{ "../../../model/transaction/_meta/fields.yml", - "../../../_meta/fields.common.yml", }, } } @@ -137,76 +135,3 @@ func TestKeywordLimitationOnTransactionAttrs(t *testing.T) { }, ) } - -func TestPayloadDataForTransaction(t *testing.T) { - // add test data for testing - // * specific edge cases - // * multiple allowed dataypes - // * regex pattern, time formats - // * length restrictions, other than keyword length restrictions - - transactionProcSetup().DataValidation(t, - []tests.SchemaTestData{ - {Key: "transaction.duration", - Valid: []interface{}{12.4}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{"123"}}}}, - {Key: "transaction.timestamp", - Valid: val{json.Number("1496170422281000")}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{"1496170422281000"}}}}, - {Key: "transaction.marks", - Valid: []interface{}{obj{}, obj{tests.Str1024: obj{tests.Str1024: 21.0, "end": -45}}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{ - "marks", - obj{"timing": obj{"start": "start"}}, - obj{"timing": obj{"start": obj{}}}, - }}, - {Msg: `validation error`, Values: val{ - obj{"timing": obj{"m*e": -45}}, - obj{"timing": obj{"m\"": -45}}, - obj{"timing": obj{"m.": -45}}, - obj{"tim*ing": obj{"start": -45}}, - obj{"tim\"ing": obj{"start": -45}}, - obj{"tim.ing": obj{"start": -45}}}}}}, - {Key: "transaction.context.custom", - Valid: val{obj{"whatever": obj{"comes": obj{"end": -45}}}, - obj{"whatever": 123}}, - Invalid: []tests.Invalid{ - {Msg: `validation error`, Values: val{obj{"what.ever": 123}, obj{"what*ever": 123}, obj{"what\"ever": 123}}}, - {Msg: `decode error`, Values: val{"context"}}}}, - {Key: "transaction.context.request.body", - Valid: []interface{}{obj{}, tests.Str1025}, - Invalid: []tests.Invalid{{Msg: `validation error`, Values: val{102}}}}, - {Key: "transaction.context.request.headers", Valid: val{ - obj{"User-Agent": "go-1.1"}, - obj{"foo-bar": "a,b"}, - obj{"foo": []interface{}{"a", "b"}}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{102, obj{"foo": obj{"bar": "a"}}}}}}, - {Key: "transaction.context.request.env", - Valid: []interface{}{obj{}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{102, "a"}}}}, - {Key: "transaction.context.request.cookies", - Valid: []interface{}{obj{}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{123, ""}}}}, - {Key: "transaction.context.response.headers", Valid: val{ - obj{"User-Agent": "go-1.1"}, - obj{"foo-bar": "a,b"}, - obj{"foo": []interface{}{"a", "b"}}}, - Invalid: []tests.Invalid{{Msg: `decode error`, Values: val{102, obj{"foo": obj{"bar": "a"}}}}}}, - {Key: "transaction.context.tags", - Valid: val{obj{tests.Str1024Special: tests.Str1024Special}, obj{tests.Str1024: 123.45}, obj{tests.Str1024: true}}, - Invalid: []tests.Invalid{ - {Msg: `decode error`, Values: val{"tags"}}, - {Msg: `validation error`, Values: val{ - obj{"invalid": tests.Str1025}, - obj{tests.Str1024: obj{}}, - obj{"invali*d": "hello"}, - obj{"invali\"d": "hello"}, - obj{"invali.d": "hello"}}}}}, - {Key: "transaction.context.user.id", - Valid: val{123, tests.Str1024Special}, - Invalid: []tests.Invalid{{Msg: `validation error`, Values: val{obj{}, tests.Str1025}}}}, - }) -} diff --git a/script/generate_notice.py b/script/generate_notice.py index b5201f6de5e..c8248ef865d 100644 --- a/script/generate_notice.py +++ b/script/generate_notice.py @@ -19,13 +19,14 @@ # Additional third-party, non-source code dependencies, to add to the CSV output. additional_third_party_deps = [{ - "name": "Red Hat Universal Base Image minimal", - "version": "8", - "url": "https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8", - "license": "Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf", - "sourceURL": "https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz", + "name": "Red Hat Universal Base Image minimal", + "version": "8", + "url": "https://catalog.redhat.com/software/containers/ubi8/ubi-minimal/5c359a62bed8bd75a2c3fba8", + "license": "Custom;https://www.redhat.com/licenses/EULA_Red_Hat_Universal_Base_Image_English_20190422.pdf", + "sourceURL": "https://oss-dependencies.elastic.co/redhat/ubi/ubi-minimal-8-source.tar.gz", }] + def read_file(filename): if not os.path.isfile(filename): print("File not found {}".format(filename)) @@ -206,7 +207,7 @@ def get_url(modpath): module.get("Version", ""), module.get("Revision", ""), license["license_summary"], - "" # source URL + "" # source URL ]) for dep in additional_third_party_deps: diff --git a/systemtest/aggregation_test.go b/systemtest/aggregation_test.go index 3f74e38e1bc..6875050caf6 100644 --- a/systemtest/aggregation_test.go +++ b/systemtest/aggregation_test.go @@ -55,23 +55,15 @@ func TestTransactionAggregation(t *testing.T) { require.NoError(t, err) // Send some transactions to the server to be aggregated. - // - // Mimic a RUM transaction by using the "page-load" transaction type, - // which causes user-agent to be parsed and included in the aggregation - // and added to the document fields. tracer := srv.Tracer() - const chromeUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36" - for _, transactionType := range []string{"backend", "page-load"} { - tx := tracer.StartTransaction("name", transactionType) - req, _ := http.NewRequest("GET", "/", nil) - req.Header.Set("User-Agent", chromeUserAgent) - tx.Context.SetHTTPRequest(req) - tx.Duration = time.Second - tx.End() - } + tx := tracer.StartTransaction("name", "backend") + req, _ := http.NewRequest("GET", "/", nil) + tx.Context.SetHTTPRequest(req) + tx.Duration = time.Second + tx.End() tracer.Flush(nil) - result := systemtest.Elasticsearch.ExpectMinDocs(t, 2, "apm-*", + result := systemtest.Elasticsearch.ExpectDocs(t, "apm-*", estest.ExistsQuery{Field: "transaction.duration.histogram"}, ) systemtest.ApproveEvents(t, t.Name(), result.Hits.Hits, "@timestamp") diff --git a/systemtest/approvals/TestTransactionAggregation.approved.json b/systemtest/approvals/TestTransactionAggregation.approved.json index 1a051d6c8fd..858696b540f 100644 --- a/systemtest/approvals/TestTransactionAggregation.approved.json +++ b/systemtest/approvals/TestTransactionAggregation.approved.json @@ -52,62 +52,6 @@ "root": true, "type": "backend" } - }, - { - "@timestamp": "dynamic", - "agent": { - "name": "go" - }, - "ecs": { - "version": "dynamic" - }, - "event": { - "ingested": "dynamic", - "outcome": "unknown" - }, - "host": { - "hostname": "beowulf", - "name": "beowulf" - }, - "observer": { - "ephemeral_id": "dynamic", - "hostname": "dynamic", - "id": "dynamic", - "type": "apm-server", - "version": "dynamic", - "version_major": "dynamic" - }, - "processor": { - "event": "metric", - "name": "metric" - }, - "service": { - "name": "systemtest", - "node": { - "name": "beowulf" - } - }, - "timeseries": { - "instance": "systemtest:name:875650e21029d5b" - }, - "transaction": { - "duration": { - "histogram": { - "counts": [ - 1 - ], - "values": [ - 1003519 - ] - } - }, - "name": "name", - "root": true, - "type": "page-load" - }, - "user_agent": { - "name": "Chrome" - } } ] } diff --git a/systemtest/export_test.go b/systemtest/export_test.go new file mode 100644 index 00000000000..b11940d7245 --- /dev/null +++ b/systemtest/export_test.go @@ -0,0 +1,81 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package systemtest_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/elastic/apm-server/systemtest/apmservertest" +) + +func exportConfigCommand(t *testing.T, args ...string) (_ *apmservertest.ServerCmd, homedir string) { + tempdir, err := ioutil.TempDir("", "systemtest") + require.NoError(t, err) + t.Cleanup(func() { os.RemoveAll(tempdir) }) + err = ioutil.WriteFile(filepath.Join(tempdir, "apm-server.yml"), nil, 0644) + require.NoError(t, err) + + allArgs := []string{"config", "--path.home", tempdir} + allArgs = append(allArgs, args...) + return apmservertest.ServerCommand("export", allArgs...), tempdir +} + +func TestExportConfigDefaults(t *testing.T) { + cmd, tempdir := exportConfigCommand(t) + out, err := cmd.CombinedOutput() + require.NoError(t, err) + + expectedConfig := strings.ReplaceAll(` +logging: + metrics: + enabled: false +path: + config: /home/apm-server + data: /home/apm-server/data + home: /home/apm-server + logs: /home/apm-server/logs +`[1:], "/home/apm-server", tempdir) + assert.Equal(t, expectedConfig, string(out)) +} + +func TestExportConfigOverrideDefaults(t *testing.T) { + cmd, tempdir := exportConfigCommand(t, + "-E", "logging.metrics.enabled=true", + ) + out, err := cmd.CombinedOutput() + require.NoError(t, err) + + expectedConfig := strings.ReplaceAll(` +logging: + metrics: + enabled: true +path: + config: /home/apm-server + data: /home/apm-server/data + home: /home/apm-server + logs: /home/apm-server/logs +`[1:], "/home/apm-server", tempdir) + assert.Equal(t, expectedConfig, string(out)) +} diff --git a/tests/ecs_migration_test.go b/tests/ecs_migration_test.go deleted file mode 100644 index b6d01a12a73..00000000000 --- a/tests/ecs_migration_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to Elasticsearch B.V. under one or more contributor -// license agreements. See the NOTICE file distributed with -// this work for additional information regarding copyright -// ownership. Elasticsearch B.V. licenses this file to you under -// the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package tests - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "gopkg.in/yaml.v2" - - "github.com/elastic/apm-server/tests/loader" -) - -func TestECSMapping(t *testing.T) { - b, err := loader.LoadDataAsBytes("../_meta/ecs-migration.yml") - require.NoError(t, err) - - type ECSFieldMigration struct { - From, To string - Index *bool - Documented *bool - } - - var ecsMigration []ECSFieldMigration - err = yaml.Unmarshal(b, &ecsMigration) - require.NoError(t, err) - - fieldNames, err := fetchFlattenedFieldNames([]string{"../_meta/fields.common.yml"}) - require.NoError(t, err) - - for _, field := range ecsMigration { - if field.Index == nil || *field.Index || (field.Documented != nil && *field.Documented) { - assert.True(t, fieldNames.Contains(field.To), "ECS field was expected in template: "+field.To) - assert.False(t, fieldNames.Contains(field.From), "6.x field was not expected in template: "+field.From) - } else { - assert.False(t, fieldNames.Contains(field.To), "not indexed field not expected in template: "+field.To) - assert.False(t, fieldNames.Contains(field.From), "not indexed field not expected in template "+field.From) - } - - } - -} diff --git a/tests/json_schema.go b/tests/json_schema.go index 864c989055e..8eeba1f180c 100644 --- a/tests/json_schema.go +++ b/tests/json_schema.go @@ -51,17 +51,6 @@ type ProcessorSetup struct { SchemaPath string } -type SchemaTestData struct { - Key string - Valid []interface{} - Invalid []Invalid - Condition Condition -} -type Invalid struct { - Msg string - Values []interface{} -} - type Condition struct { // If requirements for a field apply in case of anothers key absence, // add the key. @@ -185,31 +174,6 @@ func (ps *ProcessorSetup) KeywordLimitation(t *testing.T, keywordExceptionKeys * } } -// Test that specified values for attributes fail or pass -// the validation accordingly. -// The configuration and testing of valid attributes here is intended -// to ensure correct setup and configuration to avoid false negatives. -func (ps *ProcessorSetup) DataValidation(t *testing.T, testData []SchemaTestData) { - for _, d := range testData { - testAttrs := func(val interface{}, valid bool, msg string) { - ps.changePayload(t, d.Key, val, d.Condition, - upsertFn, func(k string) (bool, []string) { - return valid, []string{msg} - }) - } - - for _, invalid := range d.Invalid { - for _, v := range invalid.Values { - testAttrs(v, false, invalid.Msg) - } - } - for _, v := range d.Valid { - testAttrs(v, true, "") - } - - } -} - func logPayload(t *testing.T, payload interface{}) { j, _ := json.MarshalIndent(payload, "", " ") t.Log("payload:", string(j)) diff --git a/tests/system/apmserver.py b/tests/system/apmserver.py index 1f91709caf2..77e3c7e49d9 100644 --- a/tests/system/apmserver.py +++ b/tests/system/apmserver.py @@ -13,12 +13,7 @@ from elasticsearch import Elasticsearch, NotFoundError import requests -# Add libbeat/tests/system to the import path. -output = subprocess.check_output(["go", "list", "-m", "-f", "{{.Path}} {{.Dir}}", "all"]).decode("utf-8") -beats_line = [line for line in output.splitlines() if line.startswith("github.com/elastic/beats/")][0] -beats_dir = beats_line.split(" ", 2)[1] -sys.path.append(os.path.join(beats_dir, 'libbeat', 'tests', 'system')) - +import libbeat_paths from beat.beat import INTEGRATION_TESTS, TestCase, TimeoutError from helper import wait_until from es_helper import cleanup, default_pipelines diff --git a/tests/system/libbeat_paths.py b/tests/system/libbeat_paths.py new file mode 100644 index 00000000000..75e7c5b3aa1 --- /dev/null +++ b/tests/system/libbeat_paths.py @@ -0,0 +1,9 @@ +import os.path +import subprocess +import sys + +# Add libbeat/tests/system to the import path. +output = subprocess.check_output(["go", "list", "-m", "-f", "{{.Path}} {{.Dir}}", "all"]).decode("utf-8") +beats_line = [line for line in output.splitlines() if line.startswith("github.com/elastic/beats/")][0] +beats_dir = beats_line.split(" ", 2)[1] +sys.path.append(os.path.join(beats_dir, 'libbeat', 'tests', 'system')) diff --git a/tests/system/test_export.py b/tests/system/test_export.py index 3a2da401ab0..ee4ef8f61ad 100644 --- a/tests/system/test_export.py +++ b/tests/system/test_export.py @@ -12,90 +12,6 @@ class ExportCommandTest(SubCommandTest): register_pipeline_disabled = True -@integration_test -class ExportConfigDefaultTest(ExportCommandTest): - """ - Test export config subcommand. - """ - - def start_args(self): - return { - "extra_args": ["export", "config"], - "logging_args": None, - } - - def test_export_config(self): - """ - Test export default config - """ - config = yaml.load(self.command_output, Loader=Loader) - # logging settings - self.assertDictEqual( - {"metrics": {"enabled": False}, 'files': {'rotateeverybytes': 10485760}, }, config["logging"] - ) - - # template settings - self.assertDictEqual( - { - "template": { - "settings": { - "_source": {"enabled": True}, - "index": { - "codec": "best_compression", - "mapping": { - "total_fields": {"limit": 2000} - }, - "number_of_shards": 1, - }, - }, - }, - }, config["setup"]) - - -@integration_test -class ExportConfigTest(ExportCommandTest): - """ - Test export config subcommand. - """ - - def start_args(self): - return { - "extra_args": ["export", "config", - "-E", "logging.metrics.enabled=true", - "-E", "setup.template.settings.index.mapping.total_fields.limit=5", - ], - "logging_args": None, - } - - def test_export_config(self): - """ - Test export customized config - """ - config = yaml.load(self.command_output, Loader=Loader) - # logging settings - assert "metrics" in config["logging"] - self.assertDictEqual( - {"enabled": True}, config["logging"]["metrics"] - ) - - # template settings - self.assertDictEqual( - { - "template": { - "settings": { - "_source": {"enabled": True}, - "index": { - "codec": "best_compression", - "mapping": { - "total_fields": {"limit": 5} - }, - "number_of_shards": 1, - }, - }, - }, - }, config["setup"]) - - @integration_test class TestExportTemplate(ExportCommandTest): """ diff --git a/tests/system/test_tls.py b/tests/system/test_tls.py index 5d303a8bb59..686e39458d7 100644 --- a/tests/system/test_tls.py +++ b/tests/system/test_tls.py @@ -6,13 +6,12 @@ import socket import pytest from requests.packages.urllib3.exceptions import SubjectAltNameWarning -requests.packages.urllib3.disable_warnings(SubjectAltNameWarning) - from apmserver import ServerBaseTest from apmserver import TimeoutError, integration_test INTEGRATION_TESTS = os.environ.get('INTEGRATION_TESTS', False) +requests.packages.urllib3.disable_warnings(SubjectAltNameWarning) @integration_test class TestSecureServerBaseTest(ServerBaseTest): diff --git a/x-pack/apm-server/aggregation/txmetrics/aggregator.go b/x-pack/apm-server/aggregation/txmetrics/aggregator.go index ba771540e46..f92d9267637 100644 --- a/x-pack/apm-server/aggregation/txmetrics/aggregator.go +++ b/x-pack/apm-server/aggregation/txmetrics/aggregator.go @@ -53,7 +53,6 @@ type Aggregator struct { config AggregatorConfig metrics aggregatorMetrics tooManyGroupsLogger *logp.Logger - userAgentLookup *userAgentLookup mu sync.RWMutex active, inactive *metrics @@ -88,10 +87,6 @@ type AggregatorConfig struct { // to maintain in the HDR Histograms. HDRHistogramSignificantFigures // must be in the range [1,5]. HDRHistogramSignificantFigures int - - // RUMUserAgentLRUSize is the size of the LRU cache for mapping RUM - // page-load User-Agent strings to browser names. - RUMUserAgentLRUSize int } // Validate validates the aggregator config. @@ -108,9 +103,6 @@ func (config AggregatorConfig) Validate() error { if n := config.HDRHistogramSignificantFigures; n < 1 || n > 5 { return errors.Errorf("HDRHistogramSignificantFigures (%d) outside range [1,5]", n) } - if config.RUMUserAgentLRUSize <= 0 { - return errors.New("RUMUserAgentLRUSize unspecified or negative") - } return nil } @@ -122,16 +114,11 @@ func NewAggregator(config AggregatorConfig) (*Aggregator, error) { if config.Logger == nil { config.Logger = logp.NewLogger(logs.TransactionMetrics) } - ual, err := newUserAgentLookup(config.RUMUserAgentLRUSize) - if err != nil { - return nil, err - } return &Aggregator{ stopping: make(chan struct{}), stopped: make(chan struct{}), config: config, tooManyGroupsLogger: config.Logger.WithOptions(logs.WithRateLimit(tooManyGroupsLoggerRateLimit)), - userAgentLookup: ual, active: newMetrics(config.MaxTransactionGroups), inactive: newMetrics(config.MaxTransactionGroups), }, nil @@ -356,15 +343,6 @@ func (a *Aggregator) updateTransactionMetrics(key transactionAggregationKey, has } func (a *Aggregator) makeTransactionAggregationKey(tx *model.Transaction) transactionAggregationKey { - var userAgentName string - if tx.Type == "page-load" { - // The APM app in Kibana has a special case for "page-load" - // transaction types, rendering distributions by country and - // browser. We use the same logic to decide whether or not - // to include user_agent.name in the aggregation key. - userAgentName = a.userAgentLookup.getUserAgentName(tx.Metadata.UserAgent.Original) - } - return transactionAggregationKey{ traceRoot: tx.ParentID == "", transactionName: tx.Name, @@ -380,10 +358,6 @@ func (a *Aggregator) makeTransactionAggregationKey(tx *model.Transaction) transa hostname: tx.Metadata.System.Hostname(), containerID: tx.Metadata.System.Container.ID, kubernetesPodName: tx.Metadata.System.Kubernetes.PodName, - - userAgentName: userAgentName, - - // TODO(axw) clientCountryISOCode, requires geoIP lookup in apm-server. } } @@ -403,10 +377,6 @@ func makeMetricset(key transactionAggregationKey, hash uint64, ts time.Time, cou Container: model.Container{ID: key.containerID}, Kubernetes: model.Kubernetes{PodName: key.kubernetesPodName}, }, - UserAgent: model.UserAgent{ - Name: key.userAgentName, - }, - // TODO(axw) include client.geo.country_iso_code somewhere }, Event: model.MetricsetEventCategorization{ Outcome: key.transactionOutcome, @@ -456,10 +426,8 @@ type metricsMapEntry struct { } type transactionAggregationKey struct { - traceRoot bool - agentName string - // TODO(axw) requires geoIP lookup in apm-server. - //clientCountryISOCode string + traceRoot bool + agentName string containerID string hostname string kubernetesPodName string @@ -470,7 +438,6 @@ type transactionAggregationKey struct { transactionOutcome string transactionResult string transactionType string - userAgentName string } func (k *transactionAggregationKey) hash() uint64 { @@ -479,7 +446,6 @@ func (k *transactionAggregationKey) hash() uint64 { h.WriteString("1") } h.WriteString(k.agentName) - // TODO(axw) clientCountryISOCode h.WriteString(k.containerID) h.WriteString(k.hostname) h.WriteString(k.kubernetesPodName) @@ -490,7 +456,6 @@ func (k *transactionAggregationKey) hash() uint64 { h.WriteString(k.transactionOutcome) h.WriteString(k.transactionResult) h.WriteString(k.transactionType) - h.WriteString(k.userAgentName) return h.Sum64() } diff --git a/x-pack/apm-server/aggregation/txmetrics/aggregator_test.go b/x-pack/apm-server/aggregation/txmetrics/aggregator_test.go index d441741ed55..f1221a7615c 100644 --- a/x-pack/apm-server/aggregation/txmetrics/aggregator_test.go +++ b/x-pack/apm-server/aggregation/txmetrics/aggregator_test.go @@ -56,14 +56,6 @@ func TestNewAggregatorConfigInvalid(t *testing.T) { HDRHistogramSignificantFigures: 6, }, err: "HDRHistogramSignificantFigures (6) outside range [1,5]", - }, { - config: txmetrics.AggregatorConfig{ - Report: report, - MaxTransactionGroups: 1, - MetricsInterval: time.Nanosecond, - HDRHistogramSignificantFigures: 5, - }, - err: "RUMUserAgentLRUSize unspecified or negative", }} { agg, err := txmetrics.NewAggregator(test.config) require.Error(t, err) @@ -85,8 +77,7 @@ func TestProcessTransformablesOverflow(t *testing.T) { MaxTransactionGroups: 2, MetricsInterval: time.Microsecond, HDRHistogramSignificantFigures: 1, - RUMUserAgentLRUSize: 1, - Logger: logger, + Logger: logger, }) require.NoError(t, err) @@ -159,7 +150,6 @@ func TestAggregatorRun(t *testing.T) { MaxTransactionGroups: 2, MetricsInterval: 10 * time.Millisecond, HDRHistogramSignificantFigures: 1, - RUMUserAgentLRUSize: 1, }) require.NoError(t, err) @@ -224,8 +214,7 @@ func TestAggregatorRunPublishErrors(t *testing.T) { MaxTransactionGroups: 2, MetricsInterval: 10 * time.Millisecond, HDRHistogramSignificantFigures: 1, - RUMUserAgentLRUSize: 1, - Logger: logger, + Logger: logger, }) require.NoError(t, err) @@ -261,7 +250,6 @@ func TestAggregateRepresentativeCount(t *testing.T) { MaxTransactionGroups: 1, MetricsInterval: time.Microsecond, HDRHistogramSignificantFigures: 1, - RUMUserAgentLRUSize: 1, }) require.NoError(t, err) @@ -344,7 +332,6 @@ func testHDRHistogramSignificantFigures(t *testing.T, sigfigs int) { MaxTransactionGroups: 2, MetricsInterval: 10 * time.Millisecond, HDRHistogramSignificantFigures: sigfigs, - RUMUserAgentLRUSize: 1, }) require.NoError(t, err) @@ -389,7 +376,6 @@ func TestAggregationFields(t *testing.T) { MaxTransactionGroups: 1000, MetricsInterval: 100 * time.Millisecond, HDRHistogramSignificantFigures: 1, - RUMUserAgentLRUSize: 1, }) require.NoError(t, err) go agg.Run() @@ -475,30 +461,6 @@ func BenchmarkAggregateTransaction(b *testing.B) { MaxTransactionGroups: 1000, MetricsInterval: time.Minute, HDRHistogramSignificantFigures: 2, - RUMUserAgentLRUSize: 1, - }) - require.NoError(b, err) - - tx := &model.Transaction{ - Name: "T-1000", - Duration: 1, - RepresentativeCount: 1, - } - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - agg.AggregateTransaction(tx) - } - }) -} - -func BenchmarkAggregateTransactionUserAgent(b *testing.B) { - agg, err := txmetrics.NewAggregator(txmetrics.AggregatorConfig{ - Report: makeErrReporter(nil), - MaxTransactionGroups: 1000, - MetricsInterval: time.Minute, - HDRHistogramSignificantFigures: 2, - RUMUserAgentLRUSize: 1, }) require.NoError(b, err) @@ -507,7 +469,6 @@ func BenchmarkAggregateTransactionUserAgent(b *testing.B) { Duration: 1, RepresentativeCount: 1, } - tx.Metadata.UserAgent.Original = "Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20110408 conkeror/0.9.3" b.RunParallel(func(pb *testing.PB) { for pb.Next() { diff --git a/x-pack/apm-server/aggregation/txmetrics/useragent.go b/x-pack/apm-server/aggregation/txmetrics/useragent.go deleted file mode 100644 index 151563b6378..00000000000 --- a/x-pack/apm-server/aggregation/txmetrics/useragent.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one -// or more contributor license agreements. Licensed under the Elastic License; -// you may not use this file except in compliance with the Elastic License. - -package txmetrics - -import ( - lru "github.com/hashicorp/golang-lru" - "github.com/ua-parser/uap-go/uaparser" -) - -// userAgentLookup provides support for parsing User-Agent strings, to enable -// aggregating "page-load" transactions by browser name. -type userAgentLookup struct { - lru *lru.Cache - parser *uaparser.Parser -} - -func newUserAgentLookup(lruSize int) (*userAgentLookup, error) { - lru, err := lru.New(lruSize) - if err != nil { - return nil, err - } - return &userAgentLookup{ - lru: lru, - // We use a static list of patterns. - parser: uaparser.NewFromSaved(), - }, nil -} - -// getUserAgentName returns the ECS `user_agent.name` value for -// the given User-Agent string. User-Agent parsing (pattern matching) -// is expensive, so we use an LRU cache to avoid it. -func (ual *userAgentLookup) getUserAgentName(userAgent string) string { - lruValue, ok := ual.lru.Get(userAgent) - if ok { - return lruValue.(string) - } - var userAgentName string - if ua := ual.parser.ParseUserAgent(userAgent); ua != nil { - userAgentName = ua.Family - } - ual.lru.Add(userAgent, userAgentName) - return userAgentName -} diff --git a/x-pack/apm-server/main.go b/x-pack/apm-server/main.go index 8e5477beca4..9eabf9eed6a 100644 --- a/x-pack/apm-server/main.go +++ b/x-pack/apm-server/main.go @@ -57,7 +57,6 @@ func newProcessors(args beater.ServerParams) ([]namedProcessor, error) { MaxTransactionGroups: args.Config.Aggregation.Transactions.MaxTransactionGroups, MetricsInterval: args.Config.Aggregation.Transactions.Interval, HDRHistogramSignificantFigures: args.Config.Aggregation.Transactions.HDRHistogramSignificantFigures, - RUMUserAgentLRUSize: args.Config.Aggregation.Transactions.RUMUserAgentLRUSize, }) if err != nil { return nil, errors.Wrapf(err, "error creating %s", name)