diff --git a/_meta/beat.yml b/_meta/beat.yml index 9ef9edb1469..b183ca671d8 100644 --- a/_meta/beat.yml +++ b/_meta/beat.yml @@ -53,6 +53,18 @@ apm-server: # secret_token for the remote apm-servers. #secret_token: + # Enable profiling of the server, recording profile samples as events. + #profiling: + #cpu: + # Set to true to enable CPU profiling. + #enabled: false + #interval: 60s + #duration: 10s + #heap: + # Set to true to enable heap profiling. + #enabled: false + #interval: 60s + # A pipeline is a definition of processors applied to documents when ingesting them to Elasticsearch. # Using pipelines involves two steps: # (1) registering a pipeline diff --git a/apm-server.docker.yml b/apm-server.docker.yml index 875078b85aa..5acb7f44e97 100644 --- a/apm-server.docker.yml +++ b/apm-server.docker.yml @@ -53,6 +53,18 @@ apm-server: # secret_token for the remote apm-servers. #secret_token: + # Enable profiling of the server, recording profile samples as events. + #profiling: + #cpu: + # Set to true to enable CPU profiling. + #enabled: false + #interval: 60s + #duration: 10s + #heap: + # Set to true to enable heap profiling. + #enabled: false + #interval: 60s + # A pipeline is a definition of processors applied to documents when ingesting them to Elasticsearch. # Using pipelines involves two steps: # (1) registering a pipeline diff --git a/apm-server.yml b/apm-server.yml index 815c2a009ca..c8b88256e49 100644 --- a/apm-server.yml +++ b/apm-server.yml @@ -53,6 +53,18 @@ apm-server: # secret_token for the remote apm-servers. #secret_token: + # Enable profiling of the server, recording profile samples as events. + #profiling: + #cpu: + # Set to true to enable CPU profiling. + #enabled: false + #interval: 60s + #duration: 10s + #heap: + # Set to true to enable heap profiling. + #enabled: false + #interval: 60s + # A pipeline is a definition of processors applied to documents when ingesting them to Elasticsearch. # Using pipelines involves two steps: # (1) registering a pipeline diff --git a/beater/api/mux.go b/beater/api/mux.go index e10cf41de10..f75aab8eafc 100644 --- a/beater/api/mux.go +++ b/beater/api/mux.go @@ -27,6 +27,7 @@ import ( "github.com/elastic/apm-server/beater/api/asset/sourcemap" "github.com/elastic/apm-server/beater/api/config/agent" "github.com/elastic/apm-server/beater/api/intake" + "github.com/elastic/apm-server/beater/api/profile" "github.com/elastic/apm-server/beater/api/root" "github.com/elastic/apm-server/beater/config" "github.com/elastic/apm-server/beater/middleware" @@ -57,6 +58,9 @@ const ( // IntakeRUMPath defines the path to ingest monitored RUM events IntakeRUMPath = "/intake/v2/rum/events" + // ProfilePath defines the path to ingest profiles + ProfilePath = "/intake/v2/profile" + // AssetSourcemapPath defines the path to upload sourcemaps AssetSourcemapPath = "/assets/v1/sourcemaps" ) @@ -85,6 +89,15 @@ func NewMux(beaterConfig *config.Config, report publish.Reporter) (*http.ServeMu {IntakePath, backendHandler}, } + // Profiling is currently experimental, and intended for profiling the + // server itself, so we only add the route if self-profiling is enabled. + if beaterConfig.SelfInstrumentation.IsEnabled() { + if beaterConfig.SelfInstrumentation.Profiling.CPU.IsEnabled() || + beaterConfig.SelfInstrumentation.Profiling.Heap.IsEnabled() { + routeMap = append(routeMap, route{ProfilePath, profileHandler}) + } + } + for _, route := range routeMap { h, err := route.handlerFn(beaterConfig, report) if err != nil { @@ -102,6 +115,11 @@ func NewMux(beaterConfig *config.Config, report publish.Reporter) (*http.ServeMu return mux, nil } +func profileHandler(cfg *config.Config, reporter publish.Reporter) (request.Handler, error) { + h := profile.Handler(systemMetadataDecoder(cfg, emptyDecoder), transform.Config{}, reporter) + return middleware.Wrap(h, backendMiddleware(cfg, profile.MonitoringMap)...) +} + func backendHandler(cfg *config.Config, reporter publish.Reporter) (request.Handler, error) { h := intake.Handler(systemMetadataDecoder(cfg, emptyDecoder), &stream.Processor{ diff --git a/beater/api/profile/handler.go b/beater/api/profile/handler.go new file mode 100644 index 00000000000..0c1902fdfe8 --- /dev/null +++ b/beater/api/profile/handler.go @@ -0,0 +1,265 @@ +// 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 profile + +import ( + "fmt" + "io" + "net/http" + "strings" + + pprof_profile "github.com/google/pprof/profile" + "github.com/pkg/errors" + + "github.com/elastic/beats/libbeat/monitoring" + + "github.com/elastic/apm-server/beater/headers" + "github.com/elastic/apm-server/beater/request" + "github.com/elastic/apm-server/decoder" + "github.com/elastic/apm-server/model/metadata" + "github.com/elastic/apm-server/model/profile" + "github.com/elastic/apm-server/publish" + "github.com/elastic/apm-server/transform" + "github.com/elastic/apm-server/utility" + "github.com/elastic/apm-server/validation" +) + +var ( + // MonitoringMap holds a mapping for request.IDs to monitoring counters + MonitoringMap = request.MonitoringMapForRegistry(registry) + registry = monitoring.Default.NewRegistry("apm-server.profile", monitoring.PublishExpvar) +) + +const ( + // TODO(axw) include messageType in pprofContentType; needs fix in agent + pprofContentType = "application/x-protobuf" + metadataContentType = "application/json" + requestContentType = "multipart/form-data" +) + +// Handler returns a request.Handler for managing profile requests. +func Handler( + dec decoder.ReqDecoder, + transformConfig transform.Config, + report publish.Reporter, +) request.Handler { + handle := func(c *request.Context) (*result, error) { + if c.Request.Method != http.MethodPost { + return nil, requestError{ + id: request.IDResponseErrorsMethodNotAllowed, + err: errors.New("only POST requests are supported"), + } + } + if err := validateContentType(c.Request.Header, requestContentType); err != nil { + return nil, requestError{ + id: request.IDResponseErrorsValidate, + err: err, + } + } + + ok := c.RateLimiter == nil || c.RateLimiter.Allow() + if !ok { + return nil, requestError{ + id: request.IDResponseErrorsRateLimit, + err: errors.New("rate limit exceeded"), + } + } + + // Extract metadata from the request, like user-agent and remote address. + reqMeta, err := dec(c.Request) + if err != nil { + return nil, requestError{ + id: request.IDResponseErrorsDecode, + err: errors.Wrap(err, "failed to decode request metadata"), + } + } + + tctx := &transform.Context{ + RequestTime: utility.RequestTime(c.Request.Context()), + Config: transformConfig, + } + + var totalLimitRemaining int64 = 10 * 1024 * 1024 // 10 MiB ought to be enough for anybody + var profiles []*pprof_profile.Profile + mr, err := c.Request.MultipartReader() + if err != nil { + return nil, err + } + for { + part, err := mr.NextPart() + if err == io.EOF { + break + } else if err != nil { + return nil, err + } + + switch part.FormName() { + case "metadata": + if err := validateContentType(http.Header(part.Header), metadataContentType); err != nil { + return nil, requestError{ + id: request.IDResponseErrorsValidate, + err: errors.Wrap(err, "invalid metadata"), + } + } + r := &limitedReader{r: part, n: 10 * 1024 /* 10 KiB ought to be enough for anybody */} + raw, err := decoder.DecodeJSONData(r) + if err != nil { + if err, ok := r.err.(requestError); ok { + return nil, err + } + return nil, requestError{ + id: request.IDResponseErrorsDecode, + err: errors.Wrap(err, "failed to decode metadata JSON"), + } + } + for k, v := range reqMeta { + utility.InsertInMap(raw, k, v.(map[string]interface{})) + } + if err := validation.Validate(raw, metadata.ModelSchema()); err != nil { + return nil, requestError{ + id: request.IDResponseErrorsValidate, + err: errors.Wrap(err, "invalid metadata"), + } + } + metadata, err := metadata.DecodeMetadata(raw) + if err != nil { + return nil, requestError{ + id: request.IDResponseErrorsDecode, + err: errors.Wrap(err, "failed to decode metadata"), + } + } + tctx.Metadata = *metadata + + case "profile": + if err := validateContentType(http.Header(part.Header), pprofContentType); err != nil { + return nil, requestError{ + id: request.IDResponseErrorsValidate, + err: errors.Wrap(err, "invalid profile"), + } + } + r := &limitedReader{r: part, n: totalLimitRemaining} + profile, err := pprof_profile.Parse(r) + if err != nil { + if err, ok := r.err.(requestError); ok { + return nil, err + } + return nil, requestError{ + id: request.IDResponseErrorsDecode, + err: errors.Wrap(err, "failed to decode profile"), + } + } + profiles = append(profiles, profile) + totalLimitRemaining = r.n + } + } + + transformables := make([]transform.Transformable, len(profiles)) + for i, p := range profiles { + transformables[i] = profile.PprofProfile{Profile: p} + } + + if err := report(c.Request.Context(), publish.PendingReq{ + Transformables: transformables, + Tcontext: tctx, + }); err != nil { + switch err { + case publish.ErrChannelClosed: + return nil, requestError{ + id: request.IDResponseErrorsShuttingDown, + err: errors.New("server is shutting down"), + } + case publish.ErrFull: + return nil, requestError{ + id: request.IDResponseErrorsFullQueue, + err: err, + } + } + return nil, err + } + return &result{Accepted: len(transformables)}, nil + } + return func(c *request.Context) { + result, err := handle(c) + if err != nil { + switch err := err.(type) { + case requestError: + c.Result.SetWithError(err.id, err) + default: + c.Result.SetWithError(request.IDResponseErrorsInternal, err) + } + } else { + c.Result.SetWithBody(request.IDResponseValidAccepted, result) + } + c.Write() + } +} + +func validateContentType(header http.Header, contentType string) error { + got := header.Get(headers.ContentType) + if !strings.Contains(got, contentType) { + return fmt.Errorf("invalid content type %q, expected %q", got, contentType) + } + return nil +} + +// limitedReader is like io.LimitedReader, but returns a +// requestError upon detecting a request that is too large. +// +// Based on net/http.maxBytesReader. +type limitedReader struct { + r io.Reader + n int64 + err error +} + +func (l *limitedReader) Read(p []byte) (n int, err error) { + if l.err != nil || len(p) == 0 { + return 0, l.err + } + if int64(len(p)) > l.n+1 { + p = p[:l.n+1] + } + n, err = l.r.Read(p) + + if int64(n) <= l.n { + l.n -= int64(n) + l.err = err + return n, err + } + + n = int(l.n) + l.n = 0 + l.err = requestError{ + id: request.IDResponseErrorsRequestTooLarge, + err: errors.New("too large"), + } + return n, l.err +} + +type result struct { + Accepted int `json:"accepted"` +} + +type requestError struct { + id request.ResultID + err error +} + +func (e requestError) Error() string { + return e.err.Error() +} diff --git a/beater/api/profile/handler_test.go b/beater/api/profile/handler_test.go new file mode 100644 index 00000000000..ea5bb0620f9 --- /dev/null +++ b/beater/api/profile/handler_test.go @@ -0,0 +1,287 @@ +// 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 profile + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/http/httptest" + "net/textproto" + "runtime/pprof" + "strings" + "testing" + + "github.com/elastic/apm-server/beater/api/ratelimit" + "github.com/elastic/apm-server/transform" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/elastic/apm-server/beater/beatertest" + "github.com/elastic/apm-server/beater/headers" + "github.com/elastic/apm-server/beater/request" + "github.com/elastic/apm-server/decoder" + "github.com/elastic/apm-server/publish" +) + +func TestHandler(t *testing.T) { + var rateLimit, err = ratelimit.NewStore(1, 0, 0) + require.NoError(t, err) + for name, tc := range map[string]testcaseIntakeHandler{ + "MethodNotAllowed": { + r: httptest.NewRequest(http.MethodGet, "/", nil), + id: request.IDResponseErrorsMethodNotAllowed, + }, + "RequestInvalidContentType": { + r: func() *http.Request { + req := httptest.NewRequest(http.MethodPost, "/", nil) + req.Header.Set(headers.ContentType, "text/plain") + return req + }(), + id: request.IDResponseErrorsValidate, + }, + "RateLimitExceeded": { + rateLimit: rateLimit, + id: request.IDResponseErrorsRateLimit, + }, + "Closing": { + reporter: func(t *testing.T) publish.Reporter { + return beatertest.ErrorReporterFn(publish.ErrChannelClosed) + }, + id: request.IDResponseErrorsShuttingDown, + }, + "FullQueue": { + reporter: func(t *testing.T) publish.Reporter { + return beatertest.ErrorReporterFn(publish.ErrFull) + }, + id: request.IDResponseErrorsFullQueue, + }, + "Empty": { + id: request.IDResponseValidAccepted, + body: prettyJSON(map[string]interface{}{"accepted": 0}), + }, + "UnknownPartIgnored": { + id: request.IDResponseValidAccepted, + body: prettyJSON(map[string]interface{}{"accepted": 0}), + parts: []part{{ + name: "foo", + contentType: "text/plain", + body: strings.NewReader(""), + }}, + }, + + "MetadataTooLarge": { + id: request.IDResponseErrorsRequestTooLarge, + parts: []part{{ + name: "metadata", + contentType: "application/json", + body: strings.NewReader("{" + strings.Repeat(" ", 10*1024) + "}"), + }}, + }, + "MetadataInvalidContentType": { + id: request.IDResponseErrorsValidate, + parts: []part{{ + name: "metadata", + contentType: "text/plain", + body: strings.NewReader(`{"service":{"name":"foo","agent":{}}}`), + }}, + }, + "MetadataInvalidJSON": { + id: request.IDResponseErrorsDecode, + parts: []part{{ + name: "metadata", + contentType: "application/json", + body: strings.NewReader("{..."), + }}, + }, + "MetadataInvalid": { + id: request.IDResponseErrorsValidate, + parts: []part{{ + name: "metadata", + contentType: "application/json", + body: strings.NewReader("{}"), // does not validate + }}, + }, + + "Profile": { + id: request.IDResponseValidAccepted, + parts: []part{ + heapProfilePart(), + heapProfilePart(), + part{ + name: "metadata", + contentType: "application/json", + body: strings.NewReader(`{"service":{"name":"foo","agent":{}}}`), + }, + }, + body: prettyJSON(map[string]interface{}{"accepted": 2}), + reports: 1, + reporter: func(t *testing.T) publish.Reporter { + return func(ctx context.Context, req publish.PendingReq) error { + require.Len(t, req.Transformables, 2) + assert.Equal(t, "foo", *req.Tcontext.Metadata.Service.Name) + return nil + } + }, + }, + "ProfileInvalidContentType": { + id: request.IDResponseErrorsValidate, + parts: []part{{ + name: "metadata", + contentType: "text/plain", + body: strings.NewReader(""), + }}, + body: prettyJSON(map[string]interface{}{"accepted": 0}), + }, + "ProfileInvalid": { + id: request.IDResponseErrorsDecode, + parts: []part{{ + name: "profile", + contentType: "application/x-protobuf", + body: strings.NewReader("foo"), + }}, + body: prettyJSON(map[string]interface{}{"accepted": 0}), + }, + "ProfileTooLarge": { + id: request.IDResponseErrorsRequestTooLarge, + parts: []part{ + heapProfilePart(), + part{ + name: "profile", + contentType: "application/x-protobuf", + body: strings.NewReader(strings.Repeat("*", 10*1024*1024)), + }, + }, + body: prettyJSON(map[string]interface{}{"accepted": 0}), + }, + } { + t.Run(name, func(t *testing.T) { + tc.setup(t) + if tc.rateLimit != nil { + tc.c.RateLimiter = tc.rateLimit.ForIP(&http.Request{}) + } + Handler(tc.dec, transform.Config{}, tc.reporter(t))(tc.c) + + assert.Equal(t, string(tc.id), string(tc.c.Result.ID)) + resultStatus := request.MapResultIDToStatus[tc.id] + assert.Equal(t, resultStatus.Code, tc.w.Code) + assert.Equal(t, "application/json", tc.w.Header().Get(headers.ContentType)) + + assert.Zero(t, tc.reports) + if tc.id == request.IDResponseValidAccepted { + assert.Equal(t, tc.body, tc.w.Body.String()) + assert.Nil(t, tc.c.Result.Err) + } else { + assert.NotNil(t, tc.c.Result.Err) + assert.NotZero(t, tc.w.Body.Len()) + } + }) + } +} + +type testcaseIntakeHandler struct { + c *request.Context + w *httptest.ResponseRecorder + r *http.Request + dec decoder.ReqDecoder + rateLimit *ratelimit.Store + reporter func(t *testing.T) publish.Reporter + reports int + parts []part + + id request.ResultID + body string +} + +func (tc *testcaseIntakeHandler) setup(t *testing.T) { + if tc.dec == nil { + tc.dec = emptyDec + } + if tc.reporter == nil { + tc.reporter = func(t *testing.T) publish.Reporter { + return beatertest.NilReporter + } + } + if tc.reports > 0 { + orig := tc.reporter + tc.reporter = func(t *testing.T) publish.Reporter { + orig := orig(t) + return func(ctx context.Context, req publish.PendingReq) error { + tc.reports-- + return orig(ctx, req) + } + } + } + if tc.r == nil { + var buf bytes.Buffer + mpw := multipart.NewWriter(&buf) + for _, part := range tc.parts { + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", fmt.Sprintf(`form-data; name=%q`, part.name)) + h.Set("Content-Type", part.contentType) + + p, err := mpw.CreatePart(h) + require.NoError(t, err) + _, err = io.Copy(p, part.body) + require.NoError(t, err) + } + mpw.Close() + + tc.r = httptest.NewRequest(http.MethodPost, "/", &buf) + tc.r.Header.Set("Content-Type", mpw.FormDataContentType()) + } + tc.r.Header.Add("Accept", "application/json") + tc.w = httptest.NewRecorder() + tc.c = &request.Context{} + tc.c.Reset(tc.w, tc.r) +} + +func emptyDec(_ *http.Request) (map[string]interface{}, error) { + return map[string]interface{}{}, nil +} + +func heapProfilePart() part { + var buf bytes.Buffer + if err := pprof.WriteHeapProfile(&buf); err != nil { + panic(err) + } + return part{ + name: "profile", + contentType: "application/x-protobuf", + body: &buf, + } +} + +type part struct { + name string + contentType string + body io.Reader +} + +func prettyJSON(v interface{}) string { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + enc.SetIndent("", " ") + enc.Encode(v) + return buf.String() +} diff --git a/beater/beater.go b/beater/beater.go index 60c856ba35d..929f655f0eb 100644 --- a/beater/beater.go +++ b/beater/beater.go @@ -266,6 +266,19 @@ func initTracer(info beat.Info, cfg *config.Config, logger *logp.Logger) (*apm.T return tracer, nil, err } + if cfg.SelfInstrumentation.Profiling.CPU.IsEnabled() { + interval := cfg.SelfInstrumentation.Profiling.CPU.Interval + duration := cfg.SelfInstrumentation.Profiling.CPU.Duration + logger.Infof("CPU profiling: every %s for %s", interval, duration) + os.Setenv("ELASTIC_APM_CPU_PROFILE_INTERVAL", interval.String()) + os.Setenv("ELASTIC_APM_CPU_PROFILE_DURATION", duration.String()) + } + if cfg.SelfInstrumentation.Profiling.Heap.IsEnabled() { + interval := cfg.SelfInstrumentation.Profiling.Heap.Interval + logger.Infof("Heap profiling: every %s", interval) + os.Setenv("ELASTIC_APM_HEAP_PROFILE_INTERVAL", interval.String()) + } + var tracerTransport transport.Transport var lis net.Listener if cfg.SelfInstrumentation.Hosts != nil { @@ -315,6 +328,7 @@ func initTracer(info beat.Info, cfg *config.Config, logger *logp.Logger) (*apm.T return nil, nil, err } tracer.SetLogger(logp.NewLogger(logs.Tracing)) + return tracer, lis, nil } diff --git a/beater/config/config.go b/beater/config/config.go index ce45edfe3ad..386ae914c5f 100644 --- a/beater/config/config.go +++ b/beater/config/config.go @@ -41,6 +41,10 @@ const ( DefaultAPMPipeline = "apm" msgInvalidConfigAgentCfg = "invalid value for `apm-server.agent.config.cache.expiration`, only accepting full seconds" + + defaultCPUProfilingInterval = 1 * time.Minute + defaultCPUProfilingDuration = 10 * time.Second + defaultHeapProfilingInterval = 1 * time.Minute ) // Config holds configuration information nested under the key `apm-server` @@ -130,10 +134,36 @@ type Cache struct { // InstrumentationConfig holds config information about self instrumenting the APM Server type InstrumentationConfig struct { - Enabled *bool `config:"enabled"` - Environment *string `config:"environment"` - Hosts urls `config:"hosts" validate:"nonzero"` - SecretToken string `config:"secret_token"` + Enabled *bool `config:"enabled"` + Environment *string `config:"environment"` + Hosts urls `config:"hosts" validate:"nonzero"` + Profiling ProfilingConfig `config:"profiling"` + SecretToken string `config:"secret_token"` +} + +// ProfilingConfig holds config information about self profiling the APM Server +type ProfilingConfig struct { + CPU *CPUProfiling `config:"cpu"` + Heap *HeapProfiling `config:"heap"` +} + +type CPUProfiling struct { + Enabled bool `config:"enabled"` + Interval time.Duration `config:"interval" validate:"positive"` + Duration time.Duration `config:"duration" validate:"positive"` +} + +func (p *CPUProfiling) IsEnabled() bool { + return p != nil && p.Enabled +} + +type HeapProfiling struct { + Enabled bool `config:"enabled"` + Interval time.Duration `config:"interval" validate:"positive"` +} + +func (p *HeapProfiling) IsEnabled() bool { + return p != nil && p.Enabled } //Mode enumerates the APM Server env @@ -189,7 +219,21 @@ func NewConfig(version string, ucfg *common.Config) (*Config, error) { return nil, errors.New(fmt.Sprintf("Invalid regex for `exclude_from_grouping`: %v", err.Error())) } } - + if c.SelfInstrumentation.IsEnabled() { + if c.SelfInstrumentation.Profiling.CPU.IsEnabled() { + if c.SelfInstrumentation.Profiling.CPU.Interval <= 0 { + c.SelfInstrumentation.Profiling.CPU.Interval = defaultCPUProfilingInterval + } + if c.SelfInstrumentation.Profiling.CPU.Duration <= 0 { + c.SelfInstrumentation.Profiling.CPU.Duration = defaultCPUProfilingDuration + } + } + if c.SelfInstrumentation.Profiling.Heap.IsEnabled() { + if c.SelfInstrumentation.Profiling.Heap.Interval <= 0 { + c.SelfInstrumentation.Profiling.Heap.Interval = defaultHeapProfilingInterval + } + } + } return c, nil } diff --git a/docs/fields.asciidoc b/docs/fields.asciidoc index ab305bf495d..83c6da2fef9 100644 --- a/docs/fields.asciidoc +++ b/docs/fields.asciidoc @@ -14,6 +14,7 @@ grouped in the following categories: * <> * <> +* <> * <> * <> * <> @@ -1107,6 +1108,171 @@ type: keyword -- +[[exported-fields-apm-profile]] +== APM Profile fields + +Profiling-specific data for APM. + + + + +*`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.duration`*:: ++ +-- +Duration of the span, in microseconds. + + +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 diff --git a/include/fields.go b/include/fields.go index 30b605e5958..e8e1203a2a2 100644 --- a/include/fields.go +++ b/include/fields.go @@ -32,5 +32,5 @@ func init() { // AssetFieldsYml returns asset data. // This is the base64 encoded gzipped contents of fields.yml. func AssetFieldsYml() string { - return "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" + return "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" } diff --git a/model/profile/_meta/fields.yml b/model/profile/_meta/fields.yml new file mode 100644 index 00000000000..3f017a3a610 --- /dev/null +++ b/model/profile/_meta/fields.yml @@ -0,0 +1,115 @@ +- key: apm-profile + title: APM Profile + description: Profiling-specific data for APM. + fields: + - name: profile + type: group + dynamic: false + fields: + + - name: cpu + type: group + fields: + - name: ns + type: long + count: 1 + description: > + Amount of CPU time profiled, in nanoseconds. + + - name: samples + type: group + fields: + - name: count + type: long + count: 1 + description: > + Number of profile samples for the profiling period. + + - name: alloc_objects + type: group + fields: + - name: count + type: long + count: 1 + description: > + Number of objects allocated since the process started. + + - name: alloc_space + type: group + fields: + - name: bytes + type: long + count: 1 + description: > + Amount of memory allocated, in bytes, since the process started. + + - name: inuse_objects + type: group + fields: + - name: count + type: long + count: 1 + description: > + Number of objects allocated and currently in use. + + - name: inuse_space + type: group + fields: + - name: bytes + type: long + count: 1 + description: > + Amount of memory allocated, in bytes, and currently in use. + + # TODO(axw) cpu + + - name: duration + type: long + count: 1 + description: > + Duration of the span, in microseconds. + + - name: top + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + Unique ID for the top stack frame in the context of its callers. + - name: function + type: keyword + count: 1 + description: > + Function name for the top stack frame. + - name: filename + type: keyword + count: 1 + description: > + Source code filename for the top stack frame. + - name: line + type: long + count: 1 + description: > + Source code line number for the top stack frame. + + - name: stack + type: group + dynamic: false + fields: + - name: id + type: keyword + description: > + Unique ID for a stack frame in the context of its callers. + - name: function + type: keyword + description: > + Function name for a stack frame. + - name: filename + type: keyword + description: > + Source code filename for a stack frame. + - name: line + type: long + description: > + Source code line number for a stack frame. diff --git a/model/profile/profile.go b/model/profile/profile.go new file mode 100644 index 00000000000..85e4f5928b5 --- /dev/null +++ b/model/profile/profile.go @@ -0,0 +1,129 @@ +// 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 profile + +import ( + "fmt" + "hash/fnv" + "time" + + "github.com/google/pprof/profile" + + "github.com/elastic/apm-server/transform" + "github.com/elastic/apm-server/utility" + "github.com/elastic/beats/libbeat/beat" + "github.com/elastic/beats/libbeat/common" +) + +const ( + processorName = "profile" + profileDocType = "profile" +) + +var processorEntry = common.MapStr{ + "name": processorName, + "event": profileDocType, +} + +// Profile represents a complete profile. +type PprofProfile struct { + Profile *profile.Profile +} + +// Transforms transforms a Profile into a sequence of beat.Events: one per profile sample. +func (pp PprofProfile) Transform(tctx *transform.Context) []beat.Event { + // Precompute value field names for use in each event. + // TODO(axw) limit to well-known value names? + profileTimestamp := time.Unix(0, pp.Profile.TimeNanos) + valueFieldNames := make([]string, len(pp.Profile.SampleType)) + for i, sampleType := range pp.Profile.SampleType { + sampleUnit := normalizeUnit(sampleType.Unit) + valueFieldNames[i] = sampleType.Type + "." + sampleUnit + } + + samples := make([]beat.Event, len(pp.Profile.Sample)) + for i, sample := range pp.Profile.Sample { + profileFields := common.MapStr{} + if pp.Profile.DurationNanos > 0 { + profileFields["duration"] = pp.Profile.DurationNanos + } + if len(sample.Location) > 0 { + hash := fnv.New64a() + stack := make([]common.MapStr, len(sample.Location)) + for i := len(sample.Location) - 1; i >= 0; i-- { + loc := sample.Location[i] + line := loc.Line[0] // aggregated at function level + + // NOTE(axw) Currently we hash the function names so that + // we can aggregate stacks across multiple builds, or where + // binaries are not reproducible. + // + // If we decide to identify stack traces and frames using + // function addresses, then need to subtract the mapping's + // start address to eliminate the effects of ASLR, i.e. + // + // var buf [8]byte + // binary.BigEndian.PutUint64(buf[:], loc.Address-loc.Mapping.Start) + // hash.Write(buf[:]) + + hash.Write([]byte(line.Function.Name)) + fields := common.MapStr{ + "id": fmt.Sprintf("%x", hash.Sum(nil)), + "function": line.Function.Name, + } + if line.Function.Filename != "" { + utility.Set(fields, "filename", line.Function.Filename) + if line.Line > 0 { + utility.Set(fields, "line", line.Line) + } + } + stack[i] = fields + } + utility.Set(profileFields, "stack", stack) + utility.Set(profileFields, "top", stack[0]) + } + for i, v := range sample.Value { + utility.Set(profileFields, valueFieldNames[i], v) + } + event := beat.Event{ + Timestamp: profileTimestamp, + Fields: common.MapStr{ + "processor": processorEntry, + profileDocType: profileFields, + }, + } + tctx.Metadata.Set(event.Fields) + if len(sample.Label) > 0 { + labels := make(common.MapStr) + for k, v := range sample.Label { + utility.Set(labels, k, v) + } + utility.DeepUpdate(event.Fields, "labels", labels) + } + samples[i] = event + } + return samples +} + +func normalizeUnit(unit string) string { + switch unit { + case "nanoseconds": + unit = "ns" + } + return unit +} diff --git a/model/profile/profile_test.go b/model/profile/profile_test.go new file mode 100644 index 00000000000..34cfa11df87 --- /dev/null +++ b/model/profile/profile_test.go @@ -0,0 +1,132 @@ +// 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 profile_test + +import ( + "testing" + "time" + + pprof_profile "github.com/google/pprof/profile" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/elastic/apm-server/model/metadata" + "github.com/elastic/apm-server/model/profile" + "github.com/elastic/apm-server/sourcemap" + "github.com/elastic/apm-server/transform" + "github.com/elastic/beats/libbeat/beat" + "github.com/elastic/beats/libbeat/common" +) + +func TestPprofProfileTransform(t *testing.T) { + timestamp := time.Unix(123, 456) + pp := profile.PprofProfile{ + Profile: &pprof_profile.Profile{ + TimeNanos: timestamp.UnixNano(), + DurationNanos: int64(10 * time.Second), + SampleType: []*pprof_profile.ValueType{ + {Type: "cpu", Unit: "nanoseconds"}, + {Type: "inuse_space", Unit: "bytes"}, + }, + Sample: []*pprof_profile.Sample{{ + Value: []int64{123, 456}, + Label: map[string][]string{ + "key1": []string{"abc", "def"}, + "key2": []string{"ghi"}, + }, + Location: []*pprof_profile.Location{{ + Line: []pprof_profile.Line{{ + Function: &pprof_profile.Function{Name: "foo", Filename: "foo.go"}, + Line: 1, + }}, + }, { + Line: []pprof_profile.Line{{ + Function: &pprof_profile.Function{Name: "bar", Filename: "bar.go"}, + }}, + }}, + }, { + Value: []int64{123, 456}, + Label: map[string][]string{ + "key1": []string{"abc", "def"}, + "key2": []string{"ghi"}, + }, + Location: []*pprof_profile.Location{{ + Line: []pprof_profile.Line{{ + Function: &pprof_profile.Function{Name: "foo", Filename: "foo.go"}, + Line: 1, + }}, + }, { + Line: []pprof_profile.Line{{ + Function: &pprof_profile.Function{Name: "bar", Filename: "bar.go"}, + }}, + }}, + }}, + }, + } + + serviceName, env := "myService", "staging" + service := metadata.Service{ + Name: &serviceName, + Environment: &env, + } + metadata := metadata.Metadata{Service: &service} + + tctx := &transform.Context{ + Config: transform.Config{SourcemapMapper: &sourcemap.SmapMapper{}}, + Metadata: metadata, + RequestTime: time.Time{}, // not used + } + output := pp.Transform(tctx) + require.Len(t, output, 2) + assert.Equal(t, output[0], output[1]) + assert.Equal(t, beat.Event{ + Timestamp: timestamp, + Fields: common.MapStr{ + "processor": common.MapStr{"event": "profile", "name": "profile"}, + "service": common.MapStr{ + "name": "myService", + "environment": "staging", + }, + "labels": common.MapStr{ + "key1": []string{"abc", "def"}, + "key2": []string{"ghi"}, + }, + "profile": common.MapStr{ + "duration": int64(10 * time.Second), + "cpu.ns": int64(123), + "inuse_space.bytes": int64(456), + "top": common.MapStr{ + "function": "foo", + "filename": "foo.go", + "line": int64(1), + "id": "3c12369b3586048a", + }, + "stack": []common.MapStr{{ + "function": "foo", + "filename": "foo.go", + "line": int64(1), + "id": "3c12369b3586048a", + }, { + "function": "bar", + "filename": "bar.go", + "id": "003934191339461a", + }}, + }, + }, + }, output[0]) +}