def serialize(context: MetricsContext) -> List[str]: config = get_config() dimension_keys = [] dimensions_properties: Dict[str, str] = {} for dimension_set in context.get_dimensions(): keys = list(dimension_set.keys()) dimension_keys.append(keys[0:MAX_DIMENSIONS]) dimensions_properties = {**dimensions_properties, **dimension_set} def create_body() -> Dict[str, Any]: body: Dict[str, Any] = { **dimensions_properties, **context.properties, } if not config.disable_metric_extraction: body["_aws"] = { **context.meta, "CloudWatchMetrics": [ { "Dimensions": dimension_keys, "Metrics": [], "Namespace": context.namespace, }, ], } return body current_body: Dict[str, Any] = create_body() event_batches: List[str] = [] num_metrics_in_current_body = 0 for metric_name, metric in context.metrics.items(): if len(metric.values) == 1: current_body[metric_name] = metric.values[0] else: current_body[metric_name] = metric.values if not config.disable_metric_extraction: current_body["_aws"]["CloudWatchMetrics"][0]["Metrics"].append( { "Name": metric_name, "Unit": metric.unit }) num_metrics_in_current_body += 1 should_serialize: bool = num_metrics_in_current_body == MAX_METRICS_PER_EVENT if should_serialize: event_batches.append(json.dumps(current_body)) current_body = create_body() num_metrics_in_current_body = 0 if not event_batches or num_metrics_in_current_body > 0: event_batches.append(json.dumps(current_body)) return event_batches
def __init__( self, namespace: str = None, properties: Dict[str, Any] = None, dimensions: List[Dict[str, str]] = None, default_dimensions: Dict[str, str] = None, ): self.namespace: str = namespace or get_config( ).namespace or constants.DEFAULT_NAMESPACE self.properties: Dict[str, Any] = properties or {} self.dimensions: List[Dict[str, str]] = dimensions or [] self.default_dimensions: Dict[str, str] = default_dimensions or {} self.metrics: Dict[str, Metric] = {} self.should_use_default_dimensions = True self.meta: Dict[str, Any] = {"Timestamp": utils.now()}
def test_serialize_metrics_with_aggregation_disabled(): """Test log records don't contain metadata when aggregation is disabled.""" # arrange config = get_config() config.disable_metric_extraction = True expected_key = fake.word() expected_value = fake.random.randrange(0, 100) expected = {expected_key: expected_value} context = get_context() context.put_metric(expected_key, expected_value) # act result_json = serializer.serialize(context)[0] # assert assert_json_equality(result_json, expected)
# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from aws_embedded_metrics.environment import Environment from aws_embedded_metrics.logger.metrics_context import MetricsContext from aws_embedded_metrics.config import get_config from typing import Any, Awaitable, Callable, Dict Config = get_config() class MetricsLogger: def __init__( self, resolve_environment: Callable[..., Awaitable[Environment]], context: MetricsContext = None, ): self.resolve_environment = resolve_environment self.context: MetricsContext = context or MetricsContext.empty() async def flush(self) -> None: # resolve the environment and get the sink # MOST of the time this will run synchonrously # This only runs asynchronously if executing for the
def get_config(): # reload the configuration module since it is loaded on # startup and cached reload(config) return config.get_config()
import logging from aws_embedded_metrics import config from aws_embedded_metrics.environment import Environment from aws_embedded_metrics.environment.default_environment import DefaultEnvironment from aws_embedded_metrics.environment.lambda_environment import LambdaEnvironment from aws_embedded_metrics.environment.ec2_environment import EC2Environment from typing import Optional log = logging.getLogger(__name__) lambda_environment = LambdaEnvironment() ec2_environment = EC2Environment() default_environment = DefaultEnvironment() environments = [lambda_environment, ec2_environment] Config = config.get_config() class EnvironmentCache: environment: Optional[Environment] = None async def resolve_environment() -> Environment: if EnvironmentCache.environment is not None: log.debug("Environment resolved from cache.") return EnvironmentCache.environment if Config.environment: lower_configured_enviroment = Config.environment.lower() if lower_configured_enviroment == "lambda": EnvironmentCache.environment = lambda_environment
def serialize(context: MetricsContext) -> List[str]: config = get_config() dimension_keys = [] dimensions_properties: Dict[str, str] = {} for dimension_set in context.get_dimensions(): keys = list(dimension_set.keys()) dimension_keys.append(keys[0:MAX_DIMENSIONS]) dimensions_properties = {**dimensions_properties, **dimension_set} def create_body() -> Dict[str, Any]: body: Dict[str, Any] = { **dimensions_properties, **context.properties, } if not config.disable_metric_extraction: body["_aws"] = { **context.meta, "CloudWatchMetrics": [ { "Dimensions": dimension_keys, "Metrics": [], "Namespace": context.namespace, }, ], } return body current_body: Dict[str, Any] = {} event_batches: List[str] = [] num_metrics_in_current_body = 0 # Track if any given metric has data remaining to be serialized remaining_data = True # Track batch number to know where to slice metric data i = 0 while remaining_data: remaining_data = False current_body = create_body() for metric_name, metric in context.metrics.items(): if len(metric.values) == 1: current_body[metric_name] = metric.values[0] else: # Slice metric data as each batch cannot contain more than # MAX_DATAPOINTS_PER_METRIC entries for a given metric start_index = i * MAX_DATAPOINTS_PER_METRIC end_index = (i + 1) * MAX_DATAPOINTS_PER_METRIC current_body[metric_name] = metric.values[ start_index:end_index] # Make sure to consume remaining values if we sliced before the end # of the metric value list if len(metric.values) > end_index: remaining_data = True if not config.disable_metric_extraction: current_body["_aws"]["CloudWatchMetrics"][0][ "Metrics"].append({ "Name": metric_name, "Unit": metric.unit }) num_metrics_in_current_body += 1 if (num_metrics_in_current_body == MAX_METRICS_PER_EVENT): event_batches.append(json.dumps(current_body)) current_body = create_body() num_metrics_in_current_body = 0 # iter over missing datapoints i += 1 if not event_batches or num_metrics_in_current_body > 0: event_batches.append(json.dumps(current_body)) return event_batches