You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am studying how to use Prometheus in multiprocessing python code (without Gunicorn).
For now i came to following simple example with two child processes:
frommultiprocessingimportProcessimportshutilimporttime, osos.environ["PROMETHEUS_MULTIPROC_DIR"] ='./PMDir'# This environment variable must be set BEFORE the first import # from prometheus_client to ensure the library uses MultiProcessValue # (metric value class with mmap support). Otherwise, # MutexValue (non-mmap) will be used, and files won't be created.fromprometheus_clientimportstart_http_server, multiprocess, CollectorRegistry, Counteros.environ["PROMETHEUS_MULTIPROC_DIR"] ='./PMDir'# If we set it AFTER import, the library initializes # the value class = MutexValue, mmap files will not be created,# and MultiProcessCollector will have nothing to work with.# This matches the documentation's recommendation to set it # before app startup.COUNTER1=NoneCOUNTER2=NoneCOUNTER3=NoneCOUNTER4=Nonedefinit_counters(registry):
""" Initialize counters (or other metrics) and register them in the specified registry. According to MetricWrapperBase's code, if registry=None, metrics won't be registered in any registry. """globalCOUNTER1, COUNTER2, COUNTER3, COUNTER4COUNTER1=Counter('counter1', 'Incremented by the first child process', registry=registry)
COUNTER2=Counter('counter2', 'Incremented by the second child process', registry=registry)
COUNTER3=Counter('counter3', 'Incremented by all processes', registry=registry)
COUNTER4=Counter('counter4', 'Incremented by main process', registry=registry)
# We are free not to create registry object in child processes. Both f1 and f2 works as process targets.# The mmap file handling is managed at the metric object level, not the collector level.# Variation 1: create registry or not to create registry - both works as I expect.deff1():
"""First child process body. Works without manual registry creation."""init_counters(None)
whileTrue:
time.sleep(1)
print("Child process 1", os.getpid())
COUNTER1.inc()
COUNTER3.inc()
deff2():
"""Second child process body. Works with manual registry creation."""registry=CollectorRegistry()
init_counters(registry)
whileTrue:
time.sleep(2)
print("Child process 2", os.getpid())
COUNTER2.inc()
COUNTER3.inc()
if__name__=='__main__':
# Ensure the multiprocess directory exists and is emptyprome_stats=os.environ["PROMETHEUS_MULTIPROC_DIR"]
ifos.path.exists(prome_stats):
shutil.rmtree(prome_stats)
os.mkdir(prome_stats)
# Variation 2: When using MultiProcessCollector directly (see Variation 4), registry creation is optional# registry = CollectorRegistry() # Create registry for HTTP serverregistry=None# Works without registry between mpc and http server# Create MultiProcessCollector object. It reads and aggregates mmap files from PROMETHEUS_MULTIPROC_DIR.# Registering it in our registry means thar registry.collect() calls mpc.collect() and thus metrics from # mpc aggregated by registry.# MultiProcessCollector ONLY reads (mmap) files; metric saving is handled by MultiProcessValue in metrics obj.mpc=multiprocess.MultiProcessCollector(registry)
# Variation 3: If main process have to report its own metrics it can use both separate CollectorRegistry or None.# init_counters(CollectorRegistry()) # Use separate registry for main process metrics.init_counters(None) # Works without registry registration# init_counters(registry) # Metrics will duplicate if we use same registry as that one mpc registered in.# # More precisely, in this situation registry will export both mpc metrics and # # main process metrics, including overlaps# Variation 4: HTTP server can use both registry or mpc# start_http_server(8000, registry=registry) # Standard approachstart_http_server(8000, registry=mpc) # Works despite mpc not being a Collector subclass (but implements collect())p1=Process(target=f1, args=())
p1.start()
p2=Process(target=f2, args=())
p2.start()
print("collect")
try:
whileTrue:
print('main process ', os.getpid())
time.sleep(1)
COUNTER3.inc()
COUNTER4.inc()
exceptKeyboardInterrupt:
p1.terminate()
p2.terminate()
shutil.rmtree(prome_stats)
(I left my findings as comments because documentation didnt answer my questions and I can make mistakes in my assumptions)
I noticed that MultiProcessCollector implements collect() but doesn't inherit from the Collector class.
The Custom collectors documentation suggests that custom collectors should implement this interface. However, MultiProcessCollector is defined as:
classMultiProcessCollector:
"""Collector for files for multi-process mode."""def__init__(self, registry, path=None):
...
This seems contradictory since:
The class name contains "Collector"
It implements the core collect() method
It's designed to be registered in a CollectorRegistry
Could you clarify:
Is this intentional design? If yes, what's the rationale behind not inheriting from Collector?
Are there any potential compatibility risks in not following the Collector interface contract?
What are potential risks of using MultiProcessCollector object in start_http_server directly, without registry = CollectorRegistry() between them?
I want to ensure I understand this correctly for proper integration. Thanks for your insights!
The text was updated successfully, but these errors were encountered:
I am studying how to use Prometheus in multiprocessing python code (without Gunicorn).
For now i came to following simple example with two child processes:
(I left my findings as comments because documentation didnt answer my questions and I can make mistakes in my assumptions)
I noticed that
MultiProcessCollector
implementscollect()
but doesn't inherit from theCollector
class.The Custom collectors documentation suggests that custom collectors should implement this interface. However,
MultiProcessCollector
is defined as:This seems contradictory since:
collect()
methodCollectorRegistry
Could you clarify:
Collector
?Collector
interface contract?MultiProcessCollector
object instart_http_server
directly, withoutregistry = CollectorRegistry()
between them?I want to ensure I understand this correctly for proper integration. Thanks for your insights!
The text was updated successfully, but these errors were encountered: