Skip to content

How to read a footprint per tenant or per provider

A loaded system's total footprint can be sliced two ways that are easy to confuse:

  • Per tenantwho caused the impact? Demand-side: attribute the footprint to the end users (a customer, a business unit, a country) who triggered it.
  • Per providerwhere does it run? Supply-side: group the infrastructure (servers and their storage) by the cloud or hosting provider that operates it.

The first is built into e-footprint; the second is a few lines of your own grouping code.

Per tenant (demand-side)

Model one UsagePattern per tenant. Each usage pattern already carries its own attributed footprint across all tiers — end-user devices, network, server, and storage — so there is nothing to assemble by hand: you just read it.

from efootprint.constants.units import u
from efootprint.core.attribution import attributed_footprint
from efootprint.core.lifecycle_phases import LifeCyclePhases

# `system` is your already-built System, with one UsagePattern per tenant
for phase in (LifeCyclePhases.MANUFACTURING, LifeCyclePhases.USAGE):
    for tenant in system.usage_patterns:
        print(phase.value, tenant.name, attributed_footprint(tenant, phase).sum().to(u.kg))

attributed_footprint(tenant, phase) returns that tenant's hourly footprint, with every tier's contribution — end-user devices, network, server, and storage — already attributed to the usage pattern that drove it. Sum it over the modeling period with .sum() to get a single number.

Per provider (supply-side)

Cloud servers modeled as BoaviztaCloudServer carry a provider attribute whose value is the provider key (e.g. aws, gcp, scaleway), so you can bucket them straight off the model — no hand-maintained mapping. Each server's attached Storage rides along with it. Each infrastructure object's total attributed footprint, across every job and tenant that uses it, is given by attributed_footprint:

from collections import defaultdict

from efootprint.abstract_modeling_classes.empty_explainable_object import EmptyExplainableObject
from efootprint.builders.hardware.boavizta_cloud_server import BoaviztaCloudServer
from efootprint.constants.units import u
from efootprint.core.attribution import attributed_footprint
from efootprint.core.lifecycle_phases import LifeCyclePhases

# `system` is your already-built System
infra_by_provider = defaultdict(list)
for server in system.servers:
    if isinstance(server, BoaviztaCloudServer):
        # the server carries its provider; its attached storage rides along
        infra_by_provider[server.provider.value] += [server, server.storage]

for provider, infra in infra_by_provider.items():
    total = sum(
        (attributed_footprint(obj, phase)
         for obj in infra for phase in LifeCyclePhases),
        start=EmptyExplainableObject())
    print(provider, total.sum().to(u.kg))

Each provider total here combines both life-cycle phases (manufacturing and usage) into one figure — unlike the per-tenant read above, which keeps the phases separate. Drop the for phase in LifeCyclePhases loop to break a provider down per phase too.

Boundary

The provider attribute lives on BoaviztaCloudServer, the cloud-instance server type. A plain on-premise Server (and its Storage) has no provider — it is hardware you operate yourself — so the loop above skips it; group those under your own label if you want them in the breakdown. Network and end-user device impacts carry no provider either: a request crosses networks and runs on devices that no single provider owns, and modeling that allocation would be substantial work not prioritized for now. Per-provider totals therefore cover the cloud server and storage tiers only; the per-tenant view above remains the way to see the full, all-tier footprint.