Skip to content

Commit

Permalink
optionally expose expvar (#509) (#615)
Browse files Browse the repository at this point in the history
* optionally expose expvar

* add changelog and config file entries
  • Loading branch information
graphaelli authored and simitt committed Feb 7, 2018
1 parent 843f2c1 commit 17132b5
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 8 deletions.
8 changes: 8 additions & 0 deletions _meta/beat.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 ======================================

# Internal queue configuration for buffering events to be published.
Expand Down
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 ======================================

# Internal queue configuration for buffering events to be published.
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 @@ -311,3 +309,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

0 comments on commit 17132b5

Please sign in to comment.