Skip to content

Commit

Permalink
Rename telemetry to usage (#1660)
Browse files Browse the repository at this point in the history
* Rename telemetry to usage

Signed-off-by: Tsotne Tabidze <tsotne@tecton.ai>

* Update docs

Signed-off-by: Tsotne Tabidze <tsotne@tecton.ai>

* Update .prow and infra

Signed-off-by: Tsotne Tabidze <tsotne@tecton.ai>

* Rename file

Signed-off-by: Tsotne Tabidze <tsotne@tecton.ai>

* Change url

Signed-off-by: Tsotne Tabidze <tsotne@tecton.ai>

* Re-add telemetry.md for backwards-compatibility

Signed-off-by: Tsotne Tabidze <tsotne@tecton.ai>
  • Loading branch information
Tsotne Tabidze authored Jun 22, 2021
1 parent 83c76f5 commit 2013c04
Show file tree
Hide file tree
Showing 17 changed files with 112 additions and 115 deletions.
4 changes: 2 additions & 2 deletions .prow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ presubmits:
branches:
- ^v0\.(3|4)-branch$

- name: test-telemetry
- name: test-usage
decorate: true
run_if_changed: "sdk/python/.*"
spec:
containers:
- image: python:3.7
command: ["infra/scripts/test-telemetry.sh"]
command: ["infra/scripts/test-usage.sh"]
env:
- name: GOOGLE_APPLICATION_CREDENTIALS
value: /etc/gcloud/service-account.json
Expand Down
2 changes: 1 addition & 1 deletion docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
* [.feastignore](reference/feature-repository/feast-ignore.md)
* [Feast CLI reference](reference/feast-cli-commands.md)
* [Python API reference](http://rtd.feast.dev/)
* [Telemetry](reference/telemetry.md)
* [Usage](reference/usage.md)

## Feast on Kubernetes

Expand Down
10 changes: 0 additions & 10 deletions docs/advanced/telemetry.md

This file was deleted.

11 changes: 11 additions & 0 deletions docs/reference/usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Usage

### How Feast SDK usage is measured

The Feast project logs anonymous usage statistics and errors in order to inform our planning. Several client methods are tracked, beginning in Feast 0.9. Users are assigned a UUID which is sent along with the name of the method, the Feast version, the OS \(using `sys.platform`\), and the current time.

The [source code](https://github.com/feast-dev/feast/blob/master/sdk/python/feast/usage.py) is available here.

### How to disable usage logging

Set the environment variable `FEAST_USAGE` to `False`.
2 changes: 1 addition & 1 deletion infra/scripts/test-docker-compose.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ docker exec \
-e DISABLE_FEAST_SERVICE_FIXTURES=true \
--user root \
feast_jupyter_1 bash \
-c 'cd /feast/tests && python -m pip install -r requirements.txt && FEAST_TELEMETRY=False pytest e2e/ --ingestion-jar https://storage.googleapis.com/feast-jobs/spark/ingestion/feast-ingestion-spark-${FEAST_VERSION}.jar --redis-url redis:6379 --core-url core:6565 --serving-url online_serving:6566 --job-service-url jobservice:6568 --staging-path file:///shared/staging/ --kafka-brokers kafka:9092 --statsd-url prometheus_statsd:9125 --prometheus-url prometheus_statsd:9102 --feast-version develop'
-c 'cd /feast/tests && python -m pip install -r requirements.txt && FEAST_USAGE=False pytest e2e/ --ingestion-jar https://storage.googleapis.com/feast-jobs/spark/ingestion/feast-ingestion-spark-${FEAST_VERSION}.jar --redis-url redis:6379 --core-url core:6565 --serving-url online_serving:6566 --job-service-url jobservice:6568 --staging-path file:///shared/staging/ --kafka-brokers kafka:9092 --statsd-url prometheus_statsd:9125 --prometheus-url prometheus_statsd:9102 --feast-version develop'
2 changes: 1 addition & 1 deletion infra/scripts/test-end-to-end.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ make build-java-no-tests REVISION=develop
python -m pip install --upgrade pip setuptools wheel
make install-python
python -m pip install -qr tests/requirements.txt
export FEAST_TELEMETRY="False"
export FEAST_USAGE="False"

su -p postgres -c "PATH=$PATH HOME=/tmp pytest -v tests/e2e/ --feast-version develop"
2 changes: 1 addition & 1 deletion infra/scripts/test-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ python -m pip install --upgrade pip setuptools wheel
make install-python
python -m pip install -qr tests/requirements.txt

export FEAST_TELEMETRY="False"
export FEAST_USAGE="False"
pytest tests/integration --dataproc-cluster-name feast-e2e --dataproc-project kf-feast --dataproc-region us-central1 --dataproc-staging-location gs://feast-templocation-kf-feast
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ LOGS_ARTIFACT_PATH=/logs/artifacts

cd sdk/python/
pip install -e ".[ci]"
cd telemetry_tests/
cd usage_tests/
pytest --junitxml=${LOGS_ARTIFACT_PATH}/python-sdk-test-report.xml
14 changes: 7 additions & 7 deletions sdk/python/feast/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
)
from feast.protos.feast.serving.ServingService_pb2_grpc import ServingServiceStub
from feast.registry import Registry
from feast.telemetry import Telemetry
from feast.usage import Usage

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -117,7 +117,7 @@ def __init__(self, options: Optional[Dict[str, str]] = None, **kwargs):
if self._config.getboolean(opt.ENABLE_AUTH):
self._auth_metadata = feast_auth.get_auth_metadata_plugin(self._config)

self._tele = Telemetry()
self._usage = Usage()

@property
def config(self) -> Config:
Expand Down Expand Up @@ -467,7 +467,7 @@ def apply(
>>> feast_client.apply(entity)
"""

self._tele.log("apply")
self._usage.log("apply")
if project is None:
project = self.project

Expand Down Expand Up @@ -581,7 +581,7 @@ def get_entity(self, name: str, project: str = None) -> Entity:
none is found
"""

self._tele.log("get_entity")
self._usage.log("get_entity")

if project is None:
project = self.project
Expand Down Expand Up @@ -706,7 +706,7 @@ def get_feature_table(self, name: str, project: str = None) -> FeatureTable:
none is found
"""

self._tele.log("get_feature_table")
self._usage.log("get_feature_table")

if project is None:
project = self.project
Expand Down Expand Up @@ -847,7 +847,7 @@ def ingest(
>>> client.ingest(driver_ft, ft_df)
"""

self._tele.log("ingest")
self._usage.log("ingest")
if project is None:
project = self.project
if isinstance(feature_table, str):
Expand Down Expand Up @@ -972,7 +972,7 @@ def get_online_features(
{'sales:daily_transactions': [1.1,1.2], 'sales:customer_id': [0,1]}
"""

self._tele.log("get_online_features")
self._usage.log("get_online_features")
try:
response = self._serving_service.GetOnlineFeaturesV2(
GetOnlineFeaturesRequestV2(
Expand Down
4 changes: 2 additions & 2 deletions sdk/python/feast/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ class ConfigOptions(metaclass=ConfigMeta):
#: Oauth token request url
OAUTH_TOKEN_REQUEST_URL: Optional[str] = None

#: Telemetry enabled
TELEMETRY = "True"
#: Usage enabled
USAGE = "True"

#: Object store registry
REGISTRY_PATH: Optional[str] = None
Expand Down
2 changes: 1 addition & 1 deletion sdk/python/feast/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from feast.protos.feast.core.Entity_pb2 import Entity as EntityV2Proto
from feast.protos.feast.core.Entity_pb2 import EntityMeta as EntityMetaProto
from feast.protos.feast.core.Entity_pb2 import EntitySpecV2 as EntitySpecProto
from feast.telemetry import log_exceptions
from feast.usage import log_exceptions
from feast.value_type import ValueType


Expand Down
2 changes: 1 addition & 1 deletion sdk/python/feast/feature_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from feast.protos.feast.types.EntityKey_pb2 import EntityKey as EntityKeyProto
from feast.registry import Registry
from feast.repo_config import RepoConfig, load_repo_config
from feast.telemetry import log_exceptions, log_exceptions_and_usage
from feast.usage import log_exceptions, log_exceptions_and_usage
from feast.version import get_version


Expand Down
2 changes: 1 addition & 1 deletion sdk/python/feast/feature_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from feast.protos.feast.core.FeatureView_pb2 import (
MaterializationInterval as MaterializationIntervalProto,
)
from feast.telemetry import log_exceptions
from feast.usage import log_exceptions
from feast.value_type import ValueType


Expand Down
2 changes: 1 addition & 1 deletion sdk/python/feast/repo_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pydantic.typing import Dict, Optional, Union

from feast.importer import get_class_from_type
from feast.telemetry import log_exceptions
from feast.usage import log_exceptions

# These dict exists so that:
# - existing values for the online store type in featurestore.yaml files continue to work in a backwards compatible way
Expand Down
2 changes: 1 addition & 1 deletion sdk/python/feast/repo_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from feast.names import adjectives, animals
from feast.registry import Registry
from feast.repo_config import RepoConfig
from feast.telemetry import log_exceptions_and_usage
from feast.usage import log_exceptions_and_usage


def py_path_to_module(path: Path, repo_root: Path) -> str:
Expand Down
76 changes: 36 additions & 40 deletions sdk/python/feast/telemetry.py → sdk/python/feast/usage.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,76 +25,72 @@

from feast.version import get_version

TELEMETRY_ENDPOINT = (
"https://us-central1-kf-feast.cloudfunctions.net/bq_telemetry_logger"
)
USAGE_ENDPOINT = "https://us-central1-kf-feast.cloudfunctions.net/bq_telemetry_logger"
_logger = logging.getLogger(__name__)


class Telemetry:
class Usage:
def __init__(self):
self._telemetry_enabled: bool = False
self._usage_enabled: bool = False
self.check_env_and_configure()

def check_env_and_configure(self):
telemetry_enabled = (
os.getenv("FEAST_TELEMETRY", default="True") == "True"
usage_enabled = (
os.getenv("FEAST_USAGE", default="True") == "True"
) # written this way to turn the env var string into a boolean

# Check if it changed
if telemetry_enabled != self._telemetry_enabled:
self._telemetry_enabled = telemetry_enabled
if usage_enabled != self._usage_enabled:
self._usage_enabled = usage_enabled

if self._telemetry_enabled:
if self._usage_enabled:
try:
feast_home_dir = join(expanduser("~"), ".feast")
Path(feast_home_dir).mkdir(exist_ok=True)
telemetry_filepath = join(feast_home_dir, "telemetry")
usage_filepath = join(feast_home_dir, "usage")

self._is_test = (
os.getenv("FEAST_IS_TELEMETRY_TEST", "False") == "True"
)
self._telemetry_counter = {"get_online_features": 0}
self._is_test = os.getenv("FEAST_IS_USAGE_TEST", "False") == "True"
self._usage_counter = {"get_online_features": 0}

if os.path.exists(telemetry_filepath):
with open(telemetry_filepath, "r") as f:
self._telemetry_id = f.read()
if os.path.exists(usage_filepath):
with open(usage_filepath, "r") as f:
self._usage_id = f.read()
else:
self._telemetry_id = str(uuid.uuid4())
self._usage_id = str(uuid.uuid4())

with open(telemetry_filepath, "w") as f:
f.write(self._telemetry_id)
with open(usage_filepath, "w") as f:
f.write(self._usage_id)
print(
"Feast is an open source project that collects anonymized error reporting and usage statistics. To opt out or learn"
" more see https://docs.feast.dev/reference/telemetry"
" more see https://docs.feast.dev/reference/usage"
)
except Exception as e:
_logger.debug(f"Unable to configure telemetry {e}")
_logger.debug(f"Unable to configure usage {e}")

@property
def telemetry_id(self) -> Optional[str]:
if os.getenv("FEAST_FORCE_TELEMETRY_UUID"):
return os.getenv("FEAST_FORCE_TELEMETRY_UUID")
return self._telemetry_id
def usage_id(self) -> Optional[str]:
if os.getenv("FEAST_FORCE_USAGE_UUID"):
return os.getenv("FEAST_FORCE_USAGE_UUID")
return self._usage_id

def log(self, function_name: str):
self.check_env_and_configure()
if self._telemetry_enabled and self.telemetry_id:
if self._usage_enabled and self.usage_id:
if function_name == "get_online_features":
if self._telemetry_counter["get_online_features"] % 10000 != 0:
self._telemetry_counter["get_online_features"] += 1
if self._usage_counter["get_online_features"] % 10000 != 0:
self._usage_counter["get_online_features"] += 1
return

json = {
"function_name": function_name,
"telemetry_id": self.telemetry_id,
"telemetry_id": self.usage_id,
"timestamp": datetime.utcnow().isoformat(),
"version": get_version(),
"os": sys.platform,
"is_test": self._is_test,
}
try:
requests.post(TELEMETRY_ENDPOINT, json=json)
requests.post(USAGE_ENDPOINT, json=json)
except Exception as e:
if self._is_test:
raise e
Expand All @@ -104,17 +100,17 @@ def log(self, function_name: str):

def log_exception(self, error_type: str, traceback: List[Tuple[str, int, str]]):
self.check_env_and_configure()
if self._telemetry_enabled and self.telemetry_id:
if self._usage_enabled and self.usage_id:
json = {
"error_type": error_type,
"traceback": traceback,
"telemetry_id": self.telemetry_id,
"telemetry_id": self.usage_id,
"version": get_version(),
"os": sys.platform,
"is_test": self._is_test,
}
try:
requests.post(TELEMETRY_ENDPOINT, json=json)
requests.post(USAGE_ENDPOINT, json=json)
except Exception as e:
if self._is_test:
raise e
Expand All @@ -141,7 +137,7 @@ def exception_logging_wrapper(*args, **kwargs):
)
)
tb = tb.tb_next
tele.log_exception(error_type, trace_to_log)
usage.log_exception(error_type, trace_to_log)
raise
return result

Expand All @@ -153,7 +149,7 @@ def log_exceptions_and_usage(func):
def exception_logging_wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
tele.log(func.__name__)
usage.log(func.__name__)
except Exception as e:
error_type = type(e).__name__
trace_to_log = []
Expand All @@ -167,7 +163,7 @@ def exception_logging_wrapper(*args, **kwargs):
)
)
tb = tb.tb_next
tele.log_exception(error_type, trace_to_log)
usage.log_exception(error_type, trace_to_log)
raise
return result

Expand All @@ -178,5 +174,5 @@ def _trim_filename(filename: str) -> str:
return filename.split("/")[-1]


# Single global telemetry object
tele = Telemetry()
# Single global usage object
usage = Usage()
Loading

0 comments on commit 2013c04

Please sign in to comment.