|
37 | 37 |
|
38 | 38 | from elasticapm.utils import compat, starmatch_to_regex |
39 | 39 | from elasticapm.utils.logging import get_logger |
| 40 | +from elasticapm.utils.threading import IntervalTimer, ThreadManager |
40 | 41 |
|
41 | 42 | __all__ = ("setup_logging", "Config") |
42 | 43 |
|
| 44 | + |
43 | 45 | logger = get_logger("elasticapm.conf") |
44 | 46 |
|
45 | 47 |
|
@@ -338,22 +340,24 @@ class Config(_ConfigBase): |
338 | 340 | use_elastic_traceparent_header = _BoolConfigValue("USE_ELASTIC_TRACEPARENT_HEADER", default=True) |
339 | 341 |
|
340 | 342 |
|
341 | | -class VersionedConfig(object): |
| 343 | +class VersionedConfig(ThreadManager): |
342 | 344 | """ |
343 | 345 | A thin layer around Config that provides versioning |
344 | 346 | """ |
345 | 347 |
|
346 | | - __slots__ = ("_config", "_version", "_first_config", "_first_version", "_lock") |
| 348 | + __slots__ = ("_config", "_version", "_first_config", "_first_version", "_lock", "transport", "_update_thread") |
347 | 349 |
|
348 | | - def __init__(self, config_object, version): |
| 350 | + def __init__(self, config_object, version, transport=None): |
349 | 351 | """ |
350 | 352 | Create a new VersionedConfig with an initial Config object |
351 | 353 | :param config_object: the initial Config object |
352 | 354 | :param version: a version identifier for the configuration |
353 | 355 | """ |
354 | 356 | self._config = self._first_config = config_object |
355 | 357 | self._version = self._first_version = version |
| 358 | + self.transport = transport |
356 | 359 | self._lock = threading.Lock() |
| 360 | + self._update_thread = None |
357 | 361 |
|
358 | 362 | def update(self, version, **config): |
359 | 363 | """ |
@@ -399,32 +403,44 @@ def __setattr__(self, name, value): |
399 | 403 | def config_version(self): |
400 | 404 | return self._version |
401 | 405 |
|
402 | | - |
403 | | -def update_config(agent): |
404 | | - logger.debug("Checking for new config...") |
405 | | - transport = agent._transport |
406 | | - keys = {"service": {"name": agent.config.service_name}} |
407 | | - if agent.config.environment: |
408 | | - keys["service"]["environment"] = agent.config.environment |
409 | | - new_version, new_config, next_run = transport.get_config(agent.config.config_version, keys) |
410 | | - if new_version and new_config: |
411 | | - errors = agent.config.update(new_version, **new_config) |
412 | | - if errors: |
413 | | - logger.error("Error applying new configuration: %s", repr(errors)) |
414 | | - else: |
415 | | - logger.info( |
416 | | - "Applied new configuration: %s", |
417 | | - "; ".join( |
418 | | - "%s=%s" % (compat.text_type(k), compat.text_type(v)) for k, v in compat.iteritems(new_config) |
419 | | - ), |
420 | | - ) |
421 | | - elif new_version == agent.config.config_version: |
422 | | - logger.debug("Remote config unchanged") |
423 | | - elif not new_config and agent.config.changed: |
424 | | - logger.debug("Remote config disappeared, resetting to original") |
425 | | - agent.config.reset() |
426 | | - |
427 | | - return next_run |
| 406 | + def update_config(self): |
| 407 | + if not self.transport: |
| 408 | + logger.warning("No transport set for config updates, skipping") |
| 409 | + return |
| 410 | + logger.debug("Checking for new config...") |
| 411 | + keys = {"service": {"name": self.service_name}} |
| 412 | + if self.environment: |
| 413 | + keys["service"]["environment"] = self.environment |
| 414 | + new_version, new_config, next_run = self.transport.get_config(self.config_version, keys) |
| 415 | + if new_version and new_config: |
| 416 | + errors = self.update(new_version, **new_config) |
| 417 | + if errors: |
| 418 | + logger.error("Error applying new configuration: %s", repr(errors)) |
| 419 | + else: |
| 420 | + logger.info( |
| 421 | + "Applied new configuration: %s", |
| 422 | + "; ".join( |
| 423 | + "%s=%s" % (compat.text_type(k), compat.text_type(v)) for k, v in compat.iteritems(new_config) |
| 424 | + ), |
| 425 | + ) |
| 426 | + elif new_version == self.config_version: |
| 427 | + logger.debug("Remote config unchanged") |
| 428 | + elif not new_config and self.changed: |
| 429 | + logger.debug("Remote config disappeared, resetting to original") |
| 430 | + self.reset() |
| 431 | + |
| 432 | + return next_run |
| 433 | + |
| 434 | + def start_thread(self): |
| 435 | + self._update_thread = IntervalTimer( |
| 436 | + self.update_config, 1, "eapm conf updater", daemon=True, evaluate_function_interval=True |
| 437 | + ) |
| 438 | + self._update_thread.start() |
| 439 | + |
| 440 | + def stop_thread(self): |
| 441 | + if self._update_thread: |
| 442 | + self._update_thread.cancel() |
| 443 | + self._update_thread = None |
428 | 444 |
|
429 | 445 |
|
430 | 446 | def setup_logging(handler, exclude=("gunicorn", "south", "elasticapm.errors")): |
|
0 commit comments