Skip to content

Commit

Permalink
Merge pull request #151 from fvaleye/feature/add-country-url-configur…
Browse files Browse the repository at this point in the history
…ation

Add the URL of the endpoint of the CO2 Signal API as a configuration key
  • Loading branch information
fvaleye authored Mar 22, 2023
2 parents 419e41d + 64b6aa1 commit 93f6a86
Show file tree
Hide file tree
Showing 13 changed files with 80 additions and 22 deletions.
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,28 @@ pip install 'tracarbon[datadog,prometheus,kubernetes]'
| Datadog | Send the metrics to Datadog. |

### 🗺️ Locations
| **Location** | **Description** | **Source** |
|--------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Worldwide | Get the latest co2g/kwh in near real-time using the CO2 Signal API. See [here](http://api.electricitymap.org/v3/zones) for the list of available zones. | [CO2Signal API](https://www.co2signal.com) |
| Europe | Static file created from the European Environment Agency Emission for the co2g/kwh in European countries. | [EEA website](https://www.eea.europa.eu/data-and-maps/daviz/co2-emission-intensity-9#tab-googlechartid_googlechartid_googlechartid_googlechartid_chart_11111) |
| AWS | Static file of the AWS Grid emissions factors. | [cloud-carbon-coefficients](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/data/grid-emissions-factors-aws.csv) |
| **Location** | **Description** | **Source** |
|--------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Worldwide | Get the latest co2g/kwh in near real-time using the CO2Signal or ElectricityMaps APIs. See [here](http://api.electricitymap.org/v3/zones) for the list of available zones. | [CO2Signal API](https://www.co2signal.com) or [ElectricityMaps](https://static.electricitymaps.com/api/docs/index.html) |
| Europe | Static file created from the European Environment Agency Emission for the co2g/kwh in European countries. | [EEA website](https://www.eea.europa.eu/data-and-maps/daviz/co2-emission-intensity-9#tab-googlechartid_googlechartid_googlechartid_googlechartid_chart_11111) |
| AWS | Static file of the AWS Grid emissions factors. | [cloud-carbon-coefficients](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/data/grid-emissions-factors-aws.csv) |

### ⚙️ Configuration
The environment variables can be set from an environment file `.env`.

| **Parameter** | **Description** |
|-------------------------------|:-------------------------------------------------------------------------------|
| TRACARBON_CO2SIGNAL_API_KEY | The api key received from [CO2 Signal](https://www.co2signal.com). |
| TRACARBON_METRIC_PREFIX_NAME | The prefix to use in all the metrics name. |
| TRACARBON_INTERVAL_IN_SECONDS | The interval in seconds to wait between the metrics evaluation. |
| TRACARBON_LOG_LEVEL | The level to use for displaying the logs. |
| **Parameter** | **Description** |
|-------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| TRACARBON_CO2SIGNAL_API_KEY | The api key received from [CO2Signal](https://www.co2signal.com) or [ElectricityMaps](https://static.electricitymaps.com/api/docs/index.html). |
| TRACARBON_CO2SIGNAL_URL | The url of [CO2Signal](https://docs.co2signal.com/#get-latest-by-country-code) is the default endpoint to retrieve the last known state of the zone, but it could be changed to [ElectricityMaps](https://static.electricitymaps.com/api/docs/index.html#live-carbon-intensity). |
| TRACARBON_METRIC_PREFIX_NAME | The prefix to use in all the metrics name. |
| TRACARBON_INTERVAL_IN_SECONDS | The interval in seconds to wait between the metrics evaluation. |
| TRACARBON_LOG_LEVEL | The level to use for displaying the logs. |

## 🔎 Usage

**Request your API key**
- Go to https://www.co2signal.com/ and get your free API key (for non-commercial use only) for getting the latest carbon intensity from your location in near-real time.
- Go to [CO2Signal](https://www.co2signal.com/) and get your free API key for non-commercial use, or go to [ElectricityMaps](https://static.electricitymaps.com/api/docs/index.html) for commercial use.
- This API is used to retrieve the last known carbon intensity (in gCO2eq/kWh) of electricity consumed in your location.
- Set your API key in the environment variables, in the `.env` file or directly in the configuration.
- If you would like to start without an API key, it's possible, the carbon intensity will be loaded statistically from a file.
- Launch Tracarbon 🚀
Expand Down
8 changes: 6 additions & 2 deletions helm/tracarbon/templates/daemonset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ spec:
- {{ . }}
{{ end }}
env:
{{- if .Values.tracarbon.co2_signal_api_key }}
{{- if .Values.tracarbon.co2signal_api_key }}
- name: TRACARBON_CO2SIGNAL_API_KEY
value: '{{ .Values.tracarbon.co2_signal_api_key }}'
value: '{{ .Values.tracarbon.co2signal_api_key }}'
{{- end }}
{{- if .Values.tracarbon.co2signal_url }}
- name: TRACARBON_CO2SIGNAL_URL
value: '{{ .Values.tracarbon.co2signal_url }}'
{{- end }}
- name: TRACARBON_INTERVAL_IN_SECONDS
value: '{{ .Values.tracarbon.interval_in_seconds }}'
Expand Down
2 changes: 1 addition & 1 deletion helm/tracarbon/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ tracarbon:
args:
- --exporter-name=Prometheus
- --containers
co2_signal_api_key: ""
co2signal_api_key: ""
interval_in_seconds: 60
log_level: "INFO"
metric_prefix_name: "tracarbon"
Expand Down
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pytest-cov = "^4.0.0"
pytest-xdist = "^3.1.0"
pytest-clarity = "^1.0.1"
sphinx = "^6.1.3"
pydata-sphinx-theme = "^0.13.0"
pydata-sphinx-theme = "^0.13.1"
toml = "^0.10.2"
types-ujson = "^5.7.0"
datadog = "^0.44.0"
Expand Down
35 changes: 34 additions & 1 deletion tests/locations/test_country.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,40 @@ async def test_france_location_should_return_latest_known(mocker):

assert result == co2_expected
assert country.name == "fr"
assert country.co2g_kwh == 51.1
assert country.co2g_kwh == co2_expected
assert country.co2g_kwh_source == CarbonIntensitySource.CO2SignalAPI


@pytest.mark.asyncio
async def test_france_location_with_recent_api_versions_should_return_latest_known(
mocker,
):
co2_expected = 83
response = {
"zone": "FR",
"carbonIntensity": co2_expected,
"datetime": "2023-03-20T17:00:00.000Z",
"updatedAt": "2023-03-20T16:51:02.892Z",
"createdAt": "2023-03-17T17:54:01.319Z",
"emissionFactorType": "lifecycle",
"isEstimated": True,
"estimationMethod": "TIME_SLICER_AVERAGE",
}
mocker.patch.object(Country, "request", return_value=response)
co2signal_api_key = "API_KEY"

country = Country(
name="fr",
co2signal_api_key=co2signal_api_key,
co2g_kwh_source=CarbonIntensitySource.CO2SignalAPI,
co2g_kwh=co2_expected,
)

result = await country.get_latest_co2g_kwh()

assert result == co2_expected
assert country.name == "fr"
assert country.co2g_kwh == co2_expected
assert country.co2g_kwh_source == CarbonIntensitySource.CO2SignalAPI


Expand Down
1 change: 1 addition & 0 deletions tracarbon/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(
else:
self.location = Country.get_location(
co2signal_api_key=self.configuration.co2signal_api_key,
co2signal_url=self.configuration.co2signal_url,
)
if exporter:
self.exporter = exporter
Expand Down
1 change: 1 addition & 0 deletions tracarbon/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def run_metrics(
tracarbon_builder = TracarbonBuilder()
location = Country.get_location(
co2signal_api_key=tracarbon_builder.configuration.co2signal_api_key,
co2signal_url=tracarbon_builder.configuration.co2signal_url,
country_code_alpha_iso_2=country_code_alpha_iso_2,
)
metric_generators: List[MetricGenerator] = [
Expand Down
3 changes: 3 additions & 0 deletions tracarbon/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ class TracarbonConfiguration(BaseModel):
log_level: str
interval_in_seconds: int
co2signal_api_key: str
co2signal_url: str

def __init__(
self,
metric_prefix_name: str = "tracarbon",
interval_in_seconds: int = 60,
log_level: str = "INFO",
co2signal_api_key: str = "",
co2signal_url: str = "https://api.co2signal.com/v1/latest?countryCode=",
env_file_path: Optional[str] = None,
**data: Any,
) -> None:
Expand All @@ -72,5 +74,6 @@ def __init__(
co2signal_api_key=os.environ.get(
"TRACARBON_CO2SIGNAL_API_KEY", co2signal_api_key
),
co2signal_url=os.environ.get("TRACARBON_CO2SIGNAL_URL", co2signal_url),
**data,
)
2 changes: 1 addition & 1 deletion tracarbon/exporters/prometheus_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ async def launch(self, metric_generator: MetricGenerator) -> None:
)
metric_value = await metric.value()
logger.info(
f"Sending metric[{metric_name}] with value [{metric_value}] and labels{metric.format_tags()} to Prometeus."
f"Sending metric[{metric_name}] with value [{metric_value}] and labels{metric.format_tags()} to Prometheus."
)
self.prometheus_metrics[metric_name].labels(
*[tag.value for tag in metric.tags]
Expand Down
6 changes: 6 additions & 0 deletions tracarbon/general_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ def __init__(self, location: Location, **data: Any) -> None:
co2signal_api_key=data["co2signal_api_key"]
if "co2signal_api_key" in data
else location.co2signal_api_key,
co2signal_url=data["co2signal_url"]
if "co2signal_url" in data
else location.co2signal_url,
location=location,
)
super().__init__(location=location, metrics=[], **data)
Expand Down Expand Up @@ -184,6 +187,9 @@ def __init__(self, location: Location, **data: Any) -> None:
co2signal_api_key=data["co2signal_api_key"]
if "co2signal_api_key" in data
else location.co2signal_api_key,
co2signal_url=data["co2signal_url"]
if "co2signal_url" in data
else location.co2signal_url,
location=location,
)
if "kubernetes" not in data:
Expand Down
13 changes: 10 additions & 3 deletions tracarbon/locations/country.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def get_current_country(
logger.debug(f"Send request to this url: {url}, timeout {timeout}s")
text = requests.get(url, timeout=timeout).text
content_json = ujson.loads(text)
return content_json["country"].lower()
return content_json["country"]
except Exception as exception:
logger.error(f"Failed to request this url: {url}")
raise exception
Expand All @@ -65,13 +65,15 @@ def get_current_country(
def get_location(
cls,
co2signal_api_key: Optional[str] = None,
co2signal_url: Optional[str] = None,
country_code_alpha_iso_2: Optional[str] = None,
) -> "Country":
"""
Get the current location automatically: on cloud provider or a country.
:param country_code_alpha_iso_2: the alpha iso 2 country name.
:param co2signal_api_key: api key for fetching CO2 Signal API.
:param co2signal_url: api url for fetching CO2 Signal API endpoint.
:return: the country
"""
# Cloud Providers
Expand All @@ -85,6 +87,7 @@ def get_location(
if co2signal_api_key:
return cls(
co2signal_api_key=co2signal_api_key,
co2signal_url=co2signal_url,
name=country_code_alpha_iso_2,
co2g_kwh_source=CarbonIntensitySource.CO2SignalAPI,
)
Expand All @@ -107,12 +110,16 @@ async def get_latest_co2g_kwh(self) -> float:
)
if not self.co2signal_api_key:
raise CO2SignalAPIKeyIsMissing()
url = f"{self.co2signal_url}{self.name}"
response = await self.request(
url=f"https://api.co2signal.com/v1/latest?countryCode={self.name}",
url=url,
headers={"auth-token": self.co2signal_api_key},
)
try:
self.co2g_kwh = float(response["data"]["carbonIntensity"])
logger.debug(f"Response from the {url}: {response}.")
if "data" in response:
response = response["data"]
self.co2g_kwh = float(response["carbonIntensity"])
logger.info(
f"The latest carbon intensity of your country {self.name} is: {self.co2g_kwh} CO2g/kwh."
)
Expand Down
1 change: 1 addition & 0 deletions tracarbon/locations/location.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class Location(ABC, BaseModel):
name: str
co2g_kwh_source: CarbonIntensitySource = CarbonIntensitySource.FILE
co2signal_api_key: Optional[str] = None
co2signal_url: Optional[str] = None
co2g_kwh: float = 0.0

@classmethod
Expand Down

0 comments on commit 93f6a86

Please sign in to comment.