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

optionally expose expvar #509

Merged
merged 2 commits into from Jan 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Expand Up @@ -40,6 +40,7 @@ https://github.com/elastic/apm-server/compare/71df0d96445df35afe27f38bcf734a0828
- Add Kibana sourcefilter for `sourcemap.sourcemap` {pull}454[454]
- Increase default 'ConcurrentRequests' from 20 to 40{pull}492[492]
- Add Config option for excluding stack trace frames from `grouping_key` calculation {pull}482[482]
- Expose expvar {pull}509[509]

==== Deprecated

Expand Down
8 changes: 8 additions & 0 deletions _meta/beat.reference.yml
Expand Up @@ -69,3 +69,11 @@ apm-server:
# If the default index pattern at 'outputs.elasticsearch.index' is changed,
# a matching index pattern needs to be specified here.
#index_pattern: "apm-*"

# golang expvar support - https://golang.org/pkg/expvar/
#expvar:
# Set to true to Expose expvar
#enabled: false

# Url to expose expvar
#url: "/debug/vars"
8 changes: 8 additions & 0 deletions apm-server.reference.yml
Expand Up @@ -70,6 +70,14 @@ apm-server:
# a matching index pattern needs to be specified here.
#index_pattern: "apm-*"

# golang expvar support - https://golang.org/pkg/expvar/
#expvar:
# Set to true to Expose expvar
#enabled: false

# Url to expose expvar
#url: "/debug/vars"

#================================ General ======================================

# The name of the shipper that publishes the network data. It can be used to group
Expand Down
16 changes: 16 additions & 0 deletions beater/beater_test.go
Expand Up @@ -49,6 +49,10 @@ func TestBeatConfig(t *testing.T) {
"certificate": "1234cert",
},
"concurrent_requests": 15,
"expvar": map[string]interface{}{
"enabled": true,
"url": "/debug/vars",
},
"frontend": map[string]interface{}{
"enabled": true,
"rate_limit": 1000,
Expand All @@ -72,6 +76,10 @@ func TestBeatConfig(t *testing.T) {
ShutdownTimeout: 9000000000,
SecretToken: "1234random",
SSL: &SSLConfig{Enabled: &truthy, PrivateKey: "1234key", Cert: "1234cert"},
Expvar: &ExpvarConfig{
Enabled: &truthy,
Url: "/debug/vars",
},
Frontend: &FrontendConfig{
Enabled: &truthy,
RateLimit: 1000,
Expand All @@ -95,6 +103,10 @@ func TestBeatConfig(t *testing.T) {
"ssl": map[string]interface{}{
"enabled": true,
},
"expvar": map[string]interface{}{
"enabled": true,
"url": "/debug/vars",
},
"frontend": map[string]interface{}{
"enabled": true,
"source_mapping": map[string]interface{}{
Expand All @@ -113,6 +125,10 @@ func TestBeatConfig(t *testing.T) {
ShutdownTimeout: 5000000000,
SecretToken: "1234random",
SSL: &SSLConfig{Enabled: &truthy, PrivateKey: "", Cert: ""},
Expvar: &ExpvarConfig{
Enabled: &truthy,
Url: "/debug/vars",
},
Frontend: &FrontendConfig{
Enabled: &truthy,
RateLimit: 10,
Expand Down
14 changes: 14 additions & 0 deletions beater/config.go
Expand Up @@ -17,9 +17,15 @@ type Config struct {
SecretToken string `config:"secret_token"`
SSL *SSLConfig `config:"ssl"`
ConcurrentRequests int `config:"concurrent_requests" validate:"min=1"`
Expvar *ExpvarConfig `config:"expvar"`
Frontend *FrontendConfig `config:"frontend"`
}

type ExpvarConfig struct {
Enabled *bool `config:"enabled"`
Url string `config:"url"`
}

type FrontendConfig struct {
Enabled *bool `config:"enabled"`
RateLimit int `config:"rate_limit"`
Expand Down Expand Up @@ -57,6 +63,10 @@ func (c *SSLConfig) isEnabled() bool {
return c != nil && (c.Enabled == nil || *c.Enabled)
}

func (c *ExpvarConfig) isEnabled() bool {
return c != nil && (c.Enabled == nil || *c.Enabled)
}

func (c *FrontendConfig) isEnabled() bool {
return c != nil && (c.Enabled == nil || *c.Enabled)
}
Expand Down Expand Up @@ -109,5 +119,9 @@ func defaultConfig() *Config {
LibraryPattern: "node_modules|bower_components|~",
ExcludeFromGrouping: "^/webpack",
},
Expvar: &ExpvarConfig{
Enabled: new(bool),
Url: "/debug/vars",
},
}
}
6 changes: 6 additions & 0 deletions beater/handlers.go
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"crypto/subtle"
"encoding/json"
"expvar"
"fmt"
"net"
"net/http"
Expand Down Expand Up @@ -81,6 +82,11 @@ func newMuxer(config *Config, report reporter) *http.ServeMux {
mux.Handle(path, mapping.ProcessorHandler(mapping.ProcessorFactory, config, report))
}

if config.Expvar.isEnabled() {
path := config.Expvar.Url
logp.Info("Path %s added to request handler", path)
mux.Handle(path, expvar.Handler())
}
return mux
}

Expand Down
19 changes: 16 additions & 3 deletions tests/system/apmserver.py
@@ -1,7 +1,8 @@
import sys
import os
import json
import os
import shutil
import sys

sys.path.append('../../_beats/libbeat/tests/system')
from beat.beat import TestCase
from elasticsearch import Elasticsearch
Expand Down Expand Up @@ -45,9 +46,9 @@ def get_error_payload(self):


class ServerSetUpBaseTest(BaseTest):

transactions_url = 'http://localhost:8200/v1/transactions'
errors_url = 'http://localhost:8200/v1/errors'
expvar_url = 'http://localhost:8200/debug/vars'

def config(self):
return {"ssl_enabled": "false",
Expand Down Expand Up @@ -300,3 +301,15 @@ def config(self):
cfg = super(SmapCacheBaseTest, self).config()
cfg.update({"smap_cache_expiration": "1"})
return cfg


class ExpvarBaseTest(ServerBaseTest):
config_overrides = {}

def config(self):
cfg = super(ServerBaseTest, self).config()
cfg.update(self.config_overrides)
return cfg

def get_debug_vars(self):
return requests.get(self.expvar_url)
6 changes: 6 additions & 0 deletions tests/system/config/apm-server.yml.j2
Expand Up @@ -17,6 +17,12 @@ apm-server:
frontend.source_mapping.index_pattern: {{ smap_index_pattern}}
frontend.source_mapping.cache.expiration: {{ smap_cache_expiration}}
{% endif %}
{% if expvar_enabled %}
expvar.enabled: {{ expvar_enabled }}
{% endif %}
{% if expvar_url %}
expvar.url: {{ expvar_url }}
{% endif %}
############################# Setup ##########################################

{% if index_name %}
Expand Down
39 changes: 34 additions & 5 deletions tests/system/test_integration.py
@@ -1,10 +1,8 @@
from apmserver import ElasticTest, ClientSideBaseTest, SmapCacheBaseTest
from beat.beat import INTEGRATION_TESTS
import os
import json
import requests
import unittest
import time

from apmserver import ElasticTest, ExpvarBaseTest, ClientSideBaseTest, SmapCacheBaseTest
from beat.beat import INTEGRATION_TESTS


class Test(ElasticTest):
Expand Down Expand Up @@ -312,3 +310,34 @@ def test_sourcemap_cache_expiration(self):
'error',
1)
self.check_frontend_error_sourcemap(False, expected_err="No Sourcemap available for")


class ExpvarDisabledIntegrationTest(ExpvarBaseTest):
config_overrides = {"expvar_enabled": "false"}

@unittest.skipUnless(INTEGRATION_TESTS, "integration test")
def test_expvar_exists(self):
"""expvar disabled, should 404"""
r = self.get_debug_vars()
assert r.status_code == 404, r.status_code


class ExpvarEnabledIntegrationTest(ExpvarBaseTest):
config_overrides = {"expvar_enabled": "true"}

@unittest.skipUnless(INTEGRATION_TESTS, "integration test")
def test_expvar_exists(self):
"""expvar enabled, should 200"""
r = self.get_debug_vars()
assert r.status_code == 200, r.status_code


class ExpvarCustomUrlIntegrationTest(ExpvarBaseTest):
config_overrides = {"expvar_enabled": "true", "expvar_url": "/foo"}
expvar_url = ExpvarBaseTest.expvar_url.replace("/debug/vars", "/foo")

@unittest.skipUnless(INTEGRATION_TESTS, "integration test")
def test_expvar_exists(self):
"""expvar enabled, should 200"""
r = self.get_debug_vars()
assert r.status_code == 200, r.status_code
5 changes: 5 additions & 0 deletions tests/system/test_requests.py
Expand Up @@ -112,6 +112,11 @@ def test_deflate_error(self):
headers={'Content-Encoding': 'deflate', 'Content-Type': 'application/json'})
assert r.status_code == 400, r.status_code

def test_expvar_default(self):
"""expvar should not be exposed by default"""
r = requests.get(self.expvar_url)
assert r.status_code == 404, r.status_code


class SecureTest(SecureServerBaseTest):

Expand Down