Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Service specific source maps #5410

Merged
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
2d72bd9
wip
stuartnelson3 Jun 1, 2021
39344ed
fleet/es branching working
stuartnelson3 Jun 1, 2021
d2e4248
add apikey to fleetStore
stuartnelson3 Jun 3, 2021
ae01674
[sourcemap/store] comment about duplicated config
stuartnelson3 Jun 3, 2021
5b8d875
implement fleet store+test
stuartnelson3 Jun 3, 2021
5a6a1ba
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 3, 2021
b612d3f
[store/fleet] use same Transport as es client
stuartnelson3 Jun 3, 2021
c1a9d49
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 3, 2021
382e5dd
remove old sourcemap api key code
stuartnelson3 Jun 4, 2021
d100bc1
use `key` struct for fleet config cache
stuartnelson3 Jun 4, 2021
3ccda4c
flatten sourcemap config struct defn
stuartnelson3 Jun 4, 2021
679f2b5
public elasticsearch/fleet constructor methods
stuartnelson3 Jun 4, 2021
c3a8aa8
synchronize cache fetch on miss
stuartnelson3 Jun 4, 2021
c082b70
write TODO about killing piling up requests
stuartnelson3 Jun 4, 2021
c4d2b1f
Add waiters semaphore
stuartnelson3 Jun 7, 2021
22dd903
remove unnecessary else block
stuartnelson3 Jun 7, 2021
c42479e
add timeout for waiting
stuartnelson3 Jun 7, 2021
9bd9bfe
update docs
stuartnelson3 Jun 7, 2021
f112d11
update changelog
stuartnelson3 Jun 7, 2021
37e0d4a
stop configuring fleet-server http client
stuartnelson3 Jun 7, 2021
72a13fe
/s/sourcemaps/metadata/
stuartnelson3 Jun 8, 2021
543f37b
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 8, 2021
718735b
fix comment
stuartnelson3 Jun 9, 2021
dd6cff7
remove sourcemap integration test
stuartnelson3 Jun 9, 2021
be1cd15
release waiters semaphore if there's a timeout
stuartnelson3 Jun 9, 2021
041c97a
remove references to version
stuartnelson3 Jun 9, 2021
5bf422c
[store] don't make mutex publicly callable
stuartnelson3 Jun 9, 2021
6948b67
[store] check for ctx.Done() while waiting
stuartnelson3 Jun 9, 2021
345b38b
check for error when reading fleet response
stuartnelson3 Jun 9, 2021
7920d64
[store] verify rum elasticsearch config used
stuartnelson3 Jun 9, 2021
6d85b80
delete repeated types in Fetch() signature
stuartnelson3 Jun 9, 2021
4ae72bb
[store] remove waiter limit
stuartnelson3 Jun 9, 2021
3650b48
remove waiters struct member
stuartnelson3 Jun 9, 2021
7d2e73d
wrap comment to 80 char
stuartnelson3 Jun 9, 2021
6dbee91
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 10, 2021
2bbf00b
systemtest: add rate limiting test (#5430)
axw Jun 10, 2021
93f7b44
Hardcode troughput settings for cloud environment (#5402)
jalvz Jun 10, 2021
6859ecb
systemtest: fix apm-server binary injection (#5440)
axw Jun 14, 2021
71a8792
remove timeout on waiting for fetch
stuartnelson3 Jun 14, 2021
1a9676e
use provided fleetmode.Enabled()
stuartnelson3 Jun 14, 2021
47223cc
[fleet] add tls fields to config
stuartnelson3 Jun 14, 2021
fee6582
[fleet] remove kibana config references
stuartnelson3 Jun 14, 2021
503506f
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 14, 2021
90a7318
add conditional around rendering api-key
stuartnelson3 Jun 16, 2021
e864156
add tls + response decompression
stuartnelson3 Jun 16, 2021
5b3ba88
remove dead comments and move code
stuartnelson3 Jun 16, 2021
2efc10a
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 16, 2021
e339269
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 17, 2021
74b57d3
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 18, 2021
db22ff0
Update apmpackage/apm/agent/input/template.yml.hbs
stuartnelson3 Jun 22, 2021
778d0e9
Move rate limiting and service name restrictions out of processor/str…
axw Jun 19, 2021
295d1c1
docker-compose: fleet-server depends on kibana (#5496)
axw Jun 21, 2021
477822c
beater: even more refactoring (#5502)
axw Jun 21, 2021
c4dc133
Fix UBI source URL (#5506)
jmlrt Jun 22, 2021
67bb80d
systemtest: remove TestDataStream*, fix Fleet test (#5503)
axw Jun 22, 2021
1cc5077
remove sourcemap api key from manifest
stuartnelson3 Jun 22, 2021
bb2c6c9
use single fleetcfg nil check
stuartnelson3 Jun 22, 2021
65ad079
attach context to outgoing fleet request
stuartnelson3 Jun 22, 2021
7711ee4
test sourcemap url path
stuartnelson3 Jun 22, 2021
3799cd5
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 22, 2021
051baa8
remove duplicate rum enable field
stuartnelson3 Jun 22, 2021
85193f5
update fleet hosts TODO
stuartnelson3 Jun 23, 2021
77fc0a0
verify that fleet store correctly uses Protocol
stuartnelson3 Jun 23, 2021
35468ac
show fleet used if fleetcfg != nil
stuartnelson3 Jun 23, 2021
78d2f1f
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 23, 2021
d098115
Merge branch 'master' into service-specific-source-maps
stuartnelson3 Jun 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion _meta/beat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,12 @@ apm-server:
# Sourcemapping is enabled by default.
#enabled: true

# Source maps are always fetched from Elasticsearch, by default using the output.elasticsearch configuration.
# Source maps may be fetched from Elasticsearch by using the
# output.elasticsearch configuration.
# A different instance must be configured when using any other output.
# This setting only affects sourcemap reads - the output determines where sourcemaps are written.
# Note: Configuring elasticsearch is not supported if apm-server is being
# managed by Fleet.
#elasticsearch:
# Array of hosts to connect to.
# Scheme and port can be left out and will be set to the default (`http` and `9200`).
Expand Down
5 changes: 4 additions & 1 deletion apm-server.docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,12 @@ apm-server:
# Sourcemapping is enabled by default.
#enabled: true

# Source maps are always fetched from Elasticsearch, by default using the output.elasticsearch configuration.
# Source maps may be fetched from Elasticsearch by using the
# output.elasticsearch configuration.
# A different instance must be configured when using any other output.
# This setting only affects sourcemap reads - the output determines where sourcemaps are written.
# Note: Configuring elasticsearch is not supported if apm-server is being
# managed by Fleet.
#elasticsearch:
# Array of hosts to connect to.
# Scheme and port can be left out and will be set to the default (`http` and `9200`).
Expand Down
5 changes: 4 additions & 1 deletion apm-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,12 @@ apm-server:
# Sourcemapping is enabled by default.
#enabled: true

# Source maps are always fetched from Elasticsearch, by default using the output.elasticsearch configuration.
# Source maps may be fetched from Elasticsearch by using the
# output.elasticsearch configuration.
# A different instance must be configured when using any other output.
# This setting only affects sourcemap reads - the output determines where sourcemaps are written.
# Note: Configuring elasticsearch is not supported if apm-server is being
# managed by Fleet.
#elasticsearch:
# Array of hosts to connect to.
# Scheme and port can be left out and will be set to the default (`http` and `9200`).
Expand Down
6 changes: 0 additions & 6 deletions apmpackage/apm/manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,6 @@ policy_templates:
required: false
show_user: false
default: 1000
- name: sourcemap_api_key
type: text
title: RUM - API Key for Sourcemaps
required: false
description: API Key for sourcemap feature. Enter as <Id>:<API Key>
show_user: false
- name: api_key_limit
type: integer
title: Maximum number of API Keys for Agent authentication
Expand Down
24 changes: 18 additions & 6 deletions beater/beater.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package beater
import (
"context"
"net"
"net/http"
"regexp"
"runtime"
"strings"
Expand All @@ -32,6 +33,7 @@ import (

"github.com/pkg/errors"
"go.elastic.co/apm"
"go.elastic.co/apm/module/apmhttp"
"golang.org/x/sync/errgroup"

"github.com/elastic/beats/v7/libbeat/beat"
Expand Down Expand Up @@ -611,7 +613,7 @@ func newTransformConfig(beatInfo beat.Info, cfg *config.Config) (*transform.Conf
},
}

if cfg.RumConfig.Enabled && cfg.RumConfig.SourceMapping.Enabled && cfg.RumConfig.SourceMapping.ESConfig != nil {
if cfg.RumConfig.Enabled && cfg.RumConfig.SourceMapping.Enabled {
store, err := newSourcemapStore(beatInfo, cfg.RumConfig.SourceMapping)
if err != nil {
return nil, err
Expand All @@ -623,12 +625,22 @@ func newTransformConfig(beatInfo beat.Info, cfg *config.Config) (*transform.Conf
}

func newSourcemapStore(beatInfo beat.Info, cfg config.SourceMapping) (*sourcemap.Store, error) {
esClient, err := elasticsearch.NewClient(cfg.ESConfig)
if err != nil {
return nil, err
if len(cfg.Metadata) == 0 {
c, err := elasticsearch.NewClient(cfg.ESConfig)
if err != nil {
return nil, err
}
index := strings.ReplaceAll(cfg.IndexPattern, "%{[observer.version]}", beatInfo.Version)
return sourcemap.NewElasticsearchStore(c, index, cfg.Cache.Expiration)
}
index := strings.ReplaceAll(cfg.IndexPattern, "%{[observer.version]}", beatInfo.Version)
return sourcemap.NewStore(esClient, index, cfg.Cache.Expiration)

// TODO: Configure the client with fleet TLS certs, timeouts, etc.
// Fleet hands TLS certs to the child processes during the gRPC
// handshake?
c := *http.DefaultClient

c.Transport = apmhttp.WrapRoundTripper(http.DefaultTransport)
return sourcemap.NewFleetStore(&c, cfg.ESConfig.APIKey, cfg.Metadata, cfg.Cache.Expiration)
}

// WrapRunServerWithProcessors wraps runServer such that it wraps args.Reporter
Expand Down
26 changes: 26 additions & 0 deletions beater/beater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ import (
"go.uber.org/zap/zaptest/observer"

"github.com/elastic/apm-server/beater/config"
"github.com/elastic/apm-server/elasticsearch"
"github.com/elastic/apm-server/model"
"github.com/elastic/apm-server/sourcemap/test"
"github.com/elastic/beats/v7/libbeat/beat"
"github.com/elastic/beats/v7/libbeat/common"
"github.com/elastic/beats/v7/libbeat/instrumentation"
Expand Down Expand Up @@ -280,3 +282,27 @@ func TestTransformConfig(t *testing.T) {
test(true, false, false)
test(true, true, true)
}

func TestStoreUsesRUMElasticsearchConfig(t *testing.T) {
stuartnelson3 marked this conversation as resolved.
Show resolved Hide resolved
var called bool
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
called = true
w.Write([]byte(test.ValidSourcemap))
}))
defer ts.Close()

cfg := config.DefaultConfig()
cfg.RumConfig.Enabled = true
cfg.RumConfig.SourceMapping.Enabled = true
cfg.RumConfig.SourceMapping.ESConfig = elasticsearch.DefaultConfig()
cfg.RumConfig.SourceMapping.ESConfig.Hosts = []string{ts.URL}

transformConfig, err := newTransformConfig(beat.Info{Version: "1.2.3"}, cfg)
require.NoError(t, err)
// Check that the provided rum elasticsearch config was used and
// Fetch() goes to the test server.
_, err = transformConfig.RUM.SourcemapStore.Fetch(context.Background(), "app", "1.0", "/bundle/path")
require.NoError(t, err)

assert.True(t, called)
}
17 changes: 17 additions & 0 deletions beater/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ func TestUnpackConfig(t *testing.T) {
MaxRetries: 3,
Backoff: elasticsearch.DefaultBackoffConfig,
},
Metadata: []SourceMapMetadata{},
esConfigured: true,
},
LibraryPattern: "^custom",
Expand Down Expand Up @@ -292,6 +293,14 @@ func TestUnpackConfig(t *testing.T) {
"rum": map[string]interface{}{
"enabled": true,
"source_mapping": map[string]interface{}{
"metadata": []map[string]string{
{
"service.name": "opbeans-rum",
"service.version": "1.2.3",
"bundle.filepath": "/test/e2e/general-usecase/bundle.js.map",
"sourcemap.url": "http://somewhere.com/bundle.js.map",
},
},
"cache": map[string]interface{}{
"expiration": 7,
},
Expand Down Expand Up @@ -365,6 +374,14 @@ func TestUnpackConfig(t *testing.T) {
},
IndexPattern: "apm-*-sourcemap*",
ESConfig: elasticsearch.DefaultConfig(),
Metadata: []SourceMapMetadata{
{
ServiceName: "opbeans-rum",
ServiceVersion: "1.2.3",
BundleFilepath: "/test/e2e/general-usecase/bundle.js.map",
SourceMapURL: "http://somewhere.com/bundle.js.map",
},
},
},
LibraryPattern: "rum",
ExcludeFromGrouping: "^/webpack",
Expand Down
22 changes: 10 additions & 12 deletions beater/config/rum.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,13 @@ type EventRate struct {
LruSize int `config:"lru_size"`
}

// SourceMapping holds sourecemap config information
// SourceMapping holds sourcemap config information
type SourceMapping struct {
Cache Cache `config:"cache"`
Enabled bool `config:"enabled"`
IndexPattern string `config:"index_pattern"`
ESConfig *elasticsearch.Config `config:"elasticsearch"`
Metadata []SourceMapMetadata `config:"metadata"`
esConfigured bool
}

Expand All @@ -79,14 +80,13 @@ func (c *RumConfig) setup(log *logp.Logger, dataStreamsEnabled bool, outputESCfg
return errors.Wrapf(err, "Invalid regex for `exclude_from_grouping`: ")
}

var apiKey string
if c.SourceMapping.esConfigured {
if dataStreamsEnabled {
// when running under Fleet, the only setting configured is the api key
apiKey = c.SourceMapping.ESConfig.APIKey
} else {
return nil
}
if c.SourceMapping.esConfigured && len(c.SourceMapping.Metadata) > 0 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work once a new package with the changes in apmpackage/apm/agent/input/template.yml.hbs is published

return errors.New("configuring both source_mapping.elasticsearch and sourcemapping.source_maps not allowed")
}

// No need to unpack the ESConfig if SourceMapMetadata exist
if len(c.SourceMapping.Metadata) > 0 {
return nil
}

// fall back to elasticsearch output configuration for sourcemap storage if possible
Expand All @@ -98,9 +98,6 @@ func (c *RumConfig) setup(log *logp.Logger, dataStreamsEnabled bool, outputESCfg
if err := outputESCfg.Unpack(c.SourceMapping.ESConfig); err != nil {
return errors.Wrap(err, "unpacking Elasticsearch config into Sourcemap config")
}
if c.SourceMapping.ESConfig.APIKey == "" {
c.SourceMapping.ESConfig.APIKey = apiKey
}
return nil
}

Expand All @@ -119,6 +116,7 @@ func defaultSourcemapping() SourceMapping {
Cache: Cache{Expiration: defaultSourcemapCacheExpiration},
IndexPattern: defaultSourcemapIndexPattern,
ESConfig: elasticsearch.DefaultConfig(),
Metadata: []SourceMapMetadata{},
}
}

Expand Down
26 changes: 26 additions & 0 deletions beater/config/sourcemapping.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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 config

// SourceMapMetadata holds source map configuration information.
type SourceMapMetadata struct {
ServiceName string `config:"service.name"`
ServiceVersion string `config:"service.version"`
BundleFilepath string `config:"bundle.filepath"`
SourceMapURL string `config:"sourcemap.url"`
}
2 changes: 1 addition & 1 deletion changelogs/head.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ https://github.com/elastic/apm-server/compare/7.13\...master[View commits]
* Add support for histograms to metrics intake {pull}5360[5360]
* Upgrade Go to 1.16.4 {pull}5381[5381]
* Add units to metric fields {pull}5395[5395]

* Support fetching sourcemaps from fleet {pull}5410[5410]

[float]
==== Deprecated
2 changes: 1 addition & 1 deletion model/error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ func TestSourcemapping(t *testing.T) {
assert.Equal(t, 1, *event.Exception.Stacktrace[0].Lineno)

// transform with sourcemap store
store, err := sourcemap.NewStore(test.ESClientWithValidSourcemap(t), "apm-*sourcemap*", time.Minute)
store, err := sourcemap.NewElasticsearchStore(test.ESClientWithValidSourcemap(t), "apm-*sourcemap*", time.Minute)
require.NoError(t, err)
transformedWithSourcemap := event.fields(context.Background(), &transform.Config{
RUM: transform.RUMConfig{SourcemapStore: store},
Expand Down
2 changes: 1 addition & 1 deletion model/sourcemap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestInvalidateCache(t *testing.T) {
// create sourcemap store
client, err := estest.NewElasticsearchClient(estest.NewTransport(t, http.StatusOK, nil))
require.NoError(t, err)
store, err := sourcemap.NewStore(client, "foo", time.Minute)
store, err := sourcemap.NewElasticsearchStore(client, "foo", time.Minute)
require.NoError(t, err)

// transform with sourcemap store
Expand Down
2 changes: 1 addition & 1 deletion model/stacktrace_frame_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ func TestLibraryFrame(t *testing.T) {
}

func testSourcemapStore(t *testing.T, client elasticsearch.Client) *sourcemap.Store {
store, err := sourcemap.NewStore(client, "apm-*sourcemap*", time.Minute)
store, err := sourcemap.NewElasticsearchStore(client, "apm-*sourcemap*", time.Minute)
require.NoError(t, err)
return store
}
15 changes: 15 additions & 0 deletions sourcemap/es_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ import (
"io"
"io/ioutil"
"net/http"
"time"

"github.com/pkg/errors"

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

"github.com/elastic/apm-server/elasticsearch"
logs "github.com/elastic/apm-server/log"
"github.com/elastic/apm-server/utility"
)

Expand Down Expand Up @@ -65,6 +67,19 @@ type esSourcemapResponse struct {
} `json:"hits"`
}

// NewElasticsearchStore returns an instance of Store for interacting with
// sourcemaps stored in ElasticSearch.
func NewElasticsearchStore(
c elasticsearch.Client,
index string,
expiration time.Duration,
) (*Store, error) {
logger := logp.NewLogger(logs.Sourcemap)
s := &esStore{c, index, logger}

return newStore(s, logger, expiration, 10*time.Second)
}

func (s *esStore) fetch(ctx context.Context, name, version, path string) (string, error) {
statusCode, body, err := s.runSearchQuery(ctx, name, version, path)
if err != nil {
Expand Down
Loading