diff --git a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/check_value_ranges.py b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/check_value_ranges.py index 4a63d9b02..c3b8214e9 100644 --- a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/check_value_ranges.py +++ b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/check_value_ranges.py @@ -15,6 +15,13 @@ import logging from pyspark.sql import DataFrame as PySparkDataFrame from pyspark.sql.functions import col +from pyspark.sql.types import ( + StructType, + StructField, + StringType, + TimestampType, + FloatType, +) from functools import reduce from operator import or_ @@ -30,18 +37,17 @@ class CheckValueRanges(MonitoringBaseInterface, InputValidator): """ - Monitors data in a DataFrame by checking specified columns against expected value ranges. - Logs events when values exceed the specified ranges. + Monitors data in a DataFrame by checking the 'Value' column against expected ranges for specified TagNames. + Logs events when 'Value' exceeds the defined ranges for any TagName. Args: df (pyspark.sql.DataFrame): The DataFrame to monitor. - columns_ranges (dict): A dictionary where keys are column names and values are dictionaries specifying 'min' and/or + tag_ranges (dict): A dictionary where keys are TagNames and values are dictionaries specifying 'min' and/or 'max', and optionally 'inclusive_bounds' values. Example: { - 'temperature': {'min': 0, 'max': 100, 'inclusive_bounds': True}, - 'pressure': {'min': 10, 'max': 200, 'inclusive_bounds': False}, - 'humidity': {'min': 30} # Defaults to inclusive_bounds = True + 'A2PS64V0J.:ZUX09R': {'min': 0, 'max': 100, 'inclusive_bounds': True}, + 'B3TS64V0K.:ZUX09R': {'min': 10, 'max': 200, 'inclusive_bounds': False}, } Example: @@ -52,25 +58,25 @@ class CheckValueRanges(MonitoringBaseInterface, InputValidator): spark = SparkSession.builder.master("local[1]").appName("CheckValueRangesExample").getOrCreate() data = [ - (1, 25, 100), - (2, -5, 150), - (3, 50, 250), - (4, 80, 300), - (5, 100, 50), + ("A2PS64V0J.:ZUX09R", "2024-01-02 03:49:45.000", "Good", 25.0), + ("A2PS64V0J.:ZUX09R", "2024-01-02 07:53:11.000", "Good", -5.0), + ("A2PS64V0J.:ZUX09R", "2024-01-02 11:56:42.000", "Good", 50.0), + ("B3TS64V0K.:ZUX09R", "2024-01-02 16:00:12.000", "Good", 80.0), + ("A2PS64V0J.:ZUX09R", "2024-01-02 20:03:46.000", "Good", 100.0), ] - columns = ["ID", "temperature", "pressure"] + columns = ["TagName", "EventTime", "Status", "Value"] df = spark.createDataFrame(data, columns) - columns_ranges = { - "temperature": {"min": 0, "max": 100, "inclusive_bounds": False}, - "pressure": {"min": 50, "max": 200}, + tag_ranges = { + "A2PS64V0J.:ZUX09R": {"min": 0, "max": 50, "inclusive_bounds": True}, + "B3TS64V0K.:ZUX09R": {"min": 50, "max": 100, "inclusive_bounds": False}, } check_value_ranges = CheckValueRanges( df=df, - columns_ranges=columns_ranges, + tag_ranges=tag_ranges, ) result_df = check_value_ranges.check() @@ -78,15 +84,24 @@ class CheckValueRanges(MonitoringBaseInterface, InputValidator): """ df: PySparkDataFrame + tag_ranges: dict + EXPECTED_SCHEMA = StructType( + [ + StructField("TagName", StringType(), True), + StructField("EventTime", TimestampType(), True), + StructField("Status", StringType(), True), + StructField("Value", FloatType(), True), + ] + ) def __init__( self, df: PySparkDataFrame, - columns_ranges: dict, + tag_ranges: dict, ) -> None: - self.df = df - self.columns_ranges = columns_ranges + self.validate(self.EXPECTED_SCHEMA) + self.tag_ranges = tag_ranges # Configure logging self.logger = logging.getLogger(self.__class__.__name__) @@ -118,17 +133,22 @@ def settings() -> dict: def check(self) -> PySparkDataFrame: """ - Executes the value range checking logic. Identifies and logs any rows where specified - columns exceed their defined value ranges. + Executes the value range checking logic for the specified TagNames. Identifies and logs any rows + where 'Value' exceeds the defined ranges for each TagName. Returns: pyspark.sql.DataFrame: Returns the original PySpark DataFrame without changes. """ self._validate_inputs() - df = self.df - for column, range_dict in self.columns_ranges.items(): + for tag_name, range_dict in self.tag_ranges.items(): + df = self.df.filter(col("TagName") == tag_name) + + if df.count() == 0: + self.logger.warning(f"No data found for TagName '{tag_name}'.") + continue + min_value = range_dict.get("min", None) max_value = range_dict.get("max", None) inclusive_bounds = range_dict.get("inclusive_bounds", True) @@ -138,17 +158,17 @@ def check(self) -> PySparkDataFrame: # Build minimum value condition if min_value is not None: if inclusive_bounds: - min_condition = col(column) < min_value + min_condition = col("Value") < min_value else: - min_condition = col(column) <= min_value + min_condition = col("Value") <= min_value conditions.append(min_condition) # Build maximum value condition if max_value is not None: if inclusive_bounds: - max_condition = col(column) > max_value + max_condition = col("Value") > max_value else: - max_condition = col(column) >= max_value + max_condition = col("Value") >= max_value conditions.append(max_condition) if not conditions: @@ -160,31 +180,59 @@ def check(self) -> PySparkDataFrame: count = out_of_range_df.count() if count > 0: self.logger.info( - f"Found {count} rows in column '{column}' out of range." + f"Found {count} rows in 'Value' column for TagName '{tag_name}' out of range." ) out_of_range_rows = out_of_range_df.collect() for row in out_of_range_rows: - self.logger.info(f"Out of range row in column '{column}': {row}") + self.logger.info( + f"Out of range row for TagName '{tag_name}': {row}" + ) else: - self.logger.info(f"No out of range values found in column '{column}'.") + self.logger.info( + f"No out of range values found in 'Value' column for TagName '{tag_name}'." + ) return self.df def _validate_inputs(self): - if not isinstance(self.columns_ranges, dict): - raise TypeError("columns_ranges must be a dictionary.") + if not isinstance(self.tag_ranges, dict): + raise TypeError("tag_ranges must be a dictionary.") + + # Erstelle eine Liste aller verfügbaren TagNames im DataFrame + available_tags = ( + self.df.select("TagName").distinct().rdd.map(lambda row: row[0]).collect() + ) - for column, range_dict in self.columns_ranges.items(): - if column not in self.df.columns: - raise ValueError(f"Column '{column}' not found in DataFrame.") + for tag_name, range_dict in self.tag_ranges.items(): + # Überprüfung, ob der TagName ein gültiger String ist + if not isinstance(tag_name, str): + raise ValueError(f"TagName '{tag_name}' must be a string.") + # Überprüfung, ob der TagName im DataFrame existiert + if tag_name not in available_tags: + raise ValueError(f"TagName '{tag_name}' not found in DataFrame.") + + # Überprüfung, ob min und/oder max angegeben sind + if "min" not in range_dict and "max" not in range_dict: + raise ValueError( + f"TagName '{tag_name}' must have at least 'min' or 'max' specified." + ) + + # Überprüfung, ob inclusive_bounds ein boolescher Wert ist inclusive_bounds = range_dict.get("inclusive_bounds", True) if not isinstance(inclusive_bounds, bool): raise ValueError( - f"Inclusive_bounds for column '{column}' must be a boolean." + f"Inclusive_bounds for TagName '{tag_name}' must be a boolean." ) - if "min" not in range_dict and "max" not in range_dict: + # Optionale Überprüfung, ob min und max numerisch sind + min_value = range_dict.get("min", None) + max_value = range_dict.get("max", None) + if min_value is not None and not isinstance(min_value, (int, float)): + raise ValueError( + f"Minimum value for TagName '{tag_name}' must be a number." + ) + if max_value is not None and not isinstance(max_value, (int, float)): raise ValueError( - f"Column '{column}' must have at least 'min' or 'max' specified." + f"Maximum value for TagName '{tag_name}' must be a number." ) diff --git a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/flatline_detection.py b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/flatline_detection.py index e0ee88ac5..fa336d629 100644 --- a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/flatline_detection.py +++ b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/flatline_detection.py @@ -14,8 +14,15 @@ import logging from pyspark.sql import DataFrame as PySparkDataFrame -from pyspark.sql.functions import col, when, lag, count, sum +from pyspark.sql.functions import col, when, lag, sum, abs from pyspark.sql.window import Window +from pyspark.sql.types import ( + StructType, + StructField, + StringType, + TimestampType, + FloatType, +) from src.sdk.python.rtdip_sdk.pipelines.data_quality.monitoring.interfaces import ( MonitoringBaseInterface, @@ -72,6 +79,14 @@ class FlatlineDetection(MonitoringBaseInterface, InputValidator): df: PySparkDataFrame watch_columns: list tolerance_timespan: int + EXPECTED_SCHEMA = StructType( + [ + StructField("TagName", StringType(), True), + StructField("EventTime", TimestampType(), True), + StructField("Status", StringType(), True), + StructField("Value", FloatType(), True), + ] + ) def __init__( self, df: PySparkDataFrame, watch_columns: list, tolerance_timespan: int @@ -82,6 +97,7 @@ def __init__( raise ValueError("tolerance_timespan must be a positive integer.") self.df = df + self.validate(self.EXPECTED_SCHEMA) self.watch_columns = watch_columns self.tolerance_timespan = tolerance_timespan @@ -113,58 +129,37 @@ def settings() -> dict: return {} def check(self) -> PySparkDataFrame: - """ - Detects flatlining in the specified columns and logs warnings if detected. - - Returns: - pyspark.sql.DataFrame: The original PySpark DataFrame unchanged. - """ - sort_column = self.df.columns[0] - + partition_column = "TagName" + sort_column = "EventTime" + window_spec = Window.partitionBy(partition_column).orderBy(sort_column) for column in self.watch_columns: - # Flag null or zero values flagged_column = f"{column}_flatline_flag" - flagged_df = self.df.withColumn( + self.df = self.df.withColumn( flagged_column, - when((col(column).isNull()) | (col(column) == 0), 1).otherwise(0), + when((col(column).isNull()) | (col(column) == 0.0), 1).otherwise(0), ) - - # Create a group for consecutive flatline streaks group_column = f"{column}_group" - flagged_df = flagged_df.withColumn( + self.df = self.df.withColumn( group_column, - ( - col(flagged_column) - != lag(col(flagged_column), 1, 0).over(Window.orderBy(sort_column)) - ).cast("int"), - ) - flagged_df = flagged_df.withColumn( - group_column, sum(col(group_column)).over(Window.orderBy(sort_column)) + sum( + when( + col(flagged_column) + != lag(col(flagged_column), 1, 0).over(window_spec), + 1, + ).otherwise(0) + ).over(window_spec), ) - - # Count rows in each group group_counts = ( - flagged_df.filter(col(flagged_column) == 1) - .groupBy(group_column) - .count() + self.df.filter(col(flagged_column) == 1).groupBy(group_column).count() ) - - # Filter groups that exceed the tolerance large_groups = group_counts.filter(col("count") > self.tolerance_timespan) - - # Log all rows in groups exceeding tolerance - if large_groups.count() > 0: - large_group_ids = [row[group_column] for row in large_groups.collect()] - relevant_rows = ( - flagged_df.filter(col(group_column).isin(large_group_ids)) - .select(*self.df.columns) - .collect() - ) - for row in relevant_rows: + large_group_ids = [row[group_column] for row in large_groups.collect()] + if large_group_ids: + relevant_rows = self.df.filter(col(group_column).isin(large_group_ids)) + for row in relevant_rows.collect(): self.logger.warning( f"Flatlining detected in column '{column}' at row: {row}." ) else: self.logger.info(f"No flatlining detected in column '{column}'.") - return self.df diff --git a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_interval.py b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_interval.py index 4b91cd419..51beca470 100644 --- a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_interval.py +++ b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_interval.py @@ -15,6 +15,13 @@ from pyspark.sql import DataFrame as PySparkDataFrame from pyspark.sql import functions as F from pyspark.sql.window import Window +from pyspark.sql.types import ( + StructType, + StructField, + StringType, + TimestampType, + FloatType, +) from src.sdk.python.rtdip_sdk.pipelines.data_quality.monitoring.interfaces import ( MonitoringBaseInterface, @@ -65,6 +72,14 @@ class IdentifyMissingDataInterval(MonitoringBaseInterface, InputValidator): """ df: PySparkDataFrame + EXPECTED_SCHEMA = StructType( + [ + StructField("TagName", StringType(), True), + StructField("EventTime", TimestampType(), True), + StructField("Status", StringType(), True), + StructField("Value", FloatType(), True), + ] + ) def __init__( self, @@ -80,9 +95,9 @@ def __init__( self.tolerance = tolerance self.mad_multiplier = mad_multiplier self.min_tolerance = min_tolerance + self.validate(self.EXPECTED_SCHEMA) # Use global pipeline logger - self.logger_manager = LoggerManager() self.logger = self.logger_manager.create_logger("IdentifyMissingDataInterval") @@ -173,7 +188,12 @@ def check(self) -> PySparkDataFrame: missing_intervals_df = df_with_diff.filter( (F.col("TimeDeltaMs") > max_interval_with_tolerance_ms) & (F.col("StartMissing").isNotNull()) - ).select("StartMissing", F.col("EventTime").alias("EndMissing"), "TimeDeltaMs") + ).select( + "TagName", + "StartMissing", + F.col("EventTime").alias("EndMissing"), + "TimeDeltaMs", + ) # Convert time delta to readable format missing_intervals_df = missing_intervals_df.withColumn( "DurationMissing", @@ -187,13 +207,13 @@ def check(self) -> PySparkDataFrame: ), F.lit("s"), ), - ).select("StartMissing", "EndMissing", "DurationMissing") + ).select("TagName", "StartMissing", "EndMissing", "DurationMissing") missing_intervals = missing_intervals_df.collect() if missing_intervals: self.logger.info("Detected Missing Intervals:") for row in missing_intervals: self.logger.info( - f"Missing Interval from {row['StartMissing']} to {row['EndMissing']} " + f"Tag: {row['TagName']} Missing Interval from {row['StartMissing']} to {row['EndMissing']} " f"Duration: {row['DurationMissing']}" ) else: diff --git a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_pattern.py b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_pattern.py index 25edc7ccf..3c950c889 100644 --- a/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_pattern.py +++ b/src/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/identify_missing_data_pattern.py @@ -17,6 +17,13 @@ import pandas as pd from pyspark.sql import DataFrame as PySparkDataFrame from pyspark.sql import functions as F +from pyspark.sql.types import ( + StructType, + StructField, + StringType, + TimestampType, + FloatType, +) from ....logging.logger_manager import LoggerManager @@ -78,6 +85,14 @@ class IdentifyMissingDataPattern(MonitoringBaseInterface, InputValidator): """ df: PySparkDataFrame + EXPECTED_SCHEMA = StructType( + [ + StructField("TagName", StringType(), True), + StructField("EventTime", TimestampType(), True), + StructField("Status", StringType(), True), + StructField("Value", FloatType(), True), + ] + ) def __init__( self, @@ -91,9 +106,9 @@ def __init__( self.patterns = patterns self.frequency = frequency.lower() self.tolerance = tolerance + self.validate(self.EXPECTED_SCHEMA) # Configure logging - self.logger = LoggerManager().create_logger(self.__class__.__name__) @staticmethod @@ -189,81 +204,6 @@ def _validate_inputs(self): self.logger.error(error_msg) raise ValueError(error_msg) from e - # def _generate_expected_times(self, min_time, max_time) -> PySparkDataFrame: - # """ - # Generates all expected times based on the patterns and frequency within the time range. - - # Args: - # min_time (Timestamp): Start of the time range. - # max_time (Timestamp): End of the time range. - - # Returns: - # PySparkDataFrame: DataFrame containing all expected 'ExpectedTime'. - # """ - # # Floor min_time to the nearest frequency step - # if self.frequency == "minutely": - # floor_min_time = min_time.replace(second=0, microsecond=0) - # step = F.expr("INTERVAL 1 MINUTE") - # elif self.frequency == "hourly": - # floor_min_time = min_time.replace(minute=0, second=0, microsecond=0) - # step = F.expr("INTERVAL 1 HOUR") - # # Ceil max_time to include the last interval - # if self.frequency == "minutely": - # ceil_max_time = (max_time + pd.Timedelta(minutes=1)).replace( - # second=0, microsecond=0 - # ) - # elif self.frequency == "hourly": - # ceil_max_time = (max_time + pd.Timedelta(hours=1)).replace( - # minute=0, second=0, microsecond=0 - # ) - # # Create a DataFrame with a sequence of base times - # base_times_df = self.df.sparkSession.createDataFrame( - # [(floor_min_time, ceil_max_time)], ["start", "end"] - # ).select( - # F.explode( - # F.sequence( - # F.col("start").cast("timestamp"), - # F.col("end").cast("timestamp"), - # step, - # ) - # ).alias("BaseTime") - # ) - # # Generate expected times based on patterns - # expected_times = [] - # for pattern in self.patterns: - # if self.frequency == "minutely": - # seconds = pattern.get("second", 0) - # milliseconds = pattern.get("millisecond", 0) - # expected_time = ( - # F.col("BaseTime") - # + F.expr(f"INTERVAL {seconds} SECOND") - # + F.expr(f"INTERVAL {milliseconds} MILLISECOND") - # ) - # elif self.frequency == "hourly": - # minutes = pattern.get("minute", 0) - # seconds = pattern.get("second", 0) - # milliseconds = pattern.get("millisecond", 0) - # expected_time = ( - # F.col("BaseTime") - # + F.expr(f"INTERVAL {minutes} MINUTE") - # + F.expr(f"INTERVAL {seconds} SECOND") - # + F.expr(f"INTERVAL {milliseconds} MILLISECOND") - # ) - # expected_times.append(expected_time) - # # Combine all expected times into one DataFrame - # expected_times_df = base_times_df.withColumn( - # "ExpectedTime", F.explode(F.array(*expected_times)) - # ).select("ExpectedTime") - # # Remove duplicates and filter within the time range - # expected_times_df = expected_times_df.distinct().filter( - # (F.col("ExpectedTime") >= F.lit(floor_min_time)) - # & (F.col("ExpectedTime") <= F.lit(max_time)) - # ) - # self.logger.info( - # f"Generated {expected_times_df.count()} expected times based on patterns." - # ) - # return expected_times_df - def _generate_expected_times(self, min_time, max_time) -> PySparkDataFrame: floor_min_time = self._get_floor_min_time(min_time) ceil_max_time = self._get_ceil_max_time(max_time) diff --git a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_check_value_ranges.py b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_check_value_ranges.py index 7b298b41b..34261cbf7 100644 --- a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_check_value_ranges.py +++ b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_check_value_ranges.py @@ -2,6 +2,8 @@ from pyspark.sql import SparkSession from io import StringIO import logging +import os + from src.sdk.python.rtdip_sdk.pipelines.data_quality.monitoring.spark.check_value_ranges import ( CheckValueRanges, @@ -36,113 +38,90 @@ def log_capture(): @pytest.fixture def test_data(spark): data = [ - {"temperature": 50, "pressure": 100, "humidity": 50}, - {"temperature": 50, "pressure": 150, "humidity": 70}, - {"temperature": 70, "pressure": 200, "humidity": 90}, - {"temperature": 70, "pressure": 250, "humidity": 110}, - {"temperature": 90, "pressure": 300, "humidity": 130}, + ("A2PS64V0J.:ZUX09R", "2024-01-02 03:49:45.000", "Good", "1"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 07:53:11.000", "Good", "2"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 11:56:42.000", "Good", "3"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 16:00:12.000", "Good", "4"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 20:03:46.000", "Good", "5"), + ("Tag2", "2024-01-02 03:49:45.000", "Good", "1"), + ("Tag2", "2024-01-02 07:53:11.000", "Good", "2"), + ("Tag2", "2024-01-02 11:56:42.000", "Good", "3"), + ("Tag2", "2024-01-02 16:00:12.000", "Good", "4"), + ("Tag2", "2024-01-02 20:03:46.000", "Good", "5"), ] - return spark.createDataFrame(data) + return spark.createDataFrame(data, ["TagName", "EventTime", "Status", "Value"]) -def test_multiple_inclusive_bounds_options(test_data, log_capture): - columns_ranges = { - "temperature": {"min": 50, "max": 70, "inclusive_bounds_bounds": True}, - "pressure": {"min": 100, "max": 200, "inclusive_bounds": False}, - "humidity": {"min": 50, "max": 90, "inclusive_bounds": True}, +def test_basic(test_data, log_capture): + tag_ranges = { + "A2PS64V0J.:ZUX09R": {"min": 2, "max": 4, "inclusive_bounds": True}, + "Tag2": {"min": 1, "max": 5, "inclusive_bounds": False}, } - monitor = CheckValueRanges(df=test_data, columns_ranges=columns_ranges) + monitor = CheckValueRanges(test_data, tag_ranges) monitor.check() - expected_logs = [ # For temperature with inclusive_bounds='both' - "Found 1 rows in column 'temperature' out of range.", - f"Out of range row in column 'temperature': {test_data.collect()[4]}", - # For pressure with inclusive_bounds='left' - "Found 4 rows in column 'pressure' out of range.", - f"Out of range row in column 'pressure': {test_data.collect()[0]}", - f"Out of range row in column 'pressure': {test_data.collect()[2]}", - f"Out of range row in column 'pressure': {test_data.collect()[3]}", - f"Out of range row in column 'pressure': {test_data.collect()[4]}", - # For humidity with inclusive_bounds='right' - "Found 2 rows in column 'humidity' out of range.", - f"Out of range row in column 'humidity': {test_data.collect()[3]}", - f"Out of range row in column 'humidity': {test_data.collect()[4]}", + "Found 2 rows in 'Value' column for TagName 'A2PS64V0J.:ZUX09R' out of range.", + f"Out of range row for TagName 'A2PS64V0J.:ZUX09R': Row(TagName='A2PS64V0J.:ZUX09R', EventTime=datetime.datetime(2024, 1, 2, 3, 49, 45), Status='Good', Value=1.0)", + f"Out of range row for TagName 'A2PS64V0J.:ZUX09R': Row(TagName='A2PS64V0J.:ZUX09R', EventTime=datetime.datetime(2024, 1, 2, 20, 3, 46), Status='Good', Value=5.0)", + f"Found 2 rows in 'Value' column for TagName 'Tag2' out of range.", + f"Out of range row for TagName 'Tag2': Row(TagName='Tag2', EventTime=datetime.datetime(2024, 1, 2, 3, 49, 45), Status='Good', Value=1.0)", + f"Out of range row for TagName 'Tag2': Row(TagName='Tag2', EventTime=datetime.datetime(2024, 1, 2, 20, 3, 46), Status='Good', Value=5.0)", ] - log_contents = log_capture.getvalue() actual_logs = log_contents.strip().split("\n") - assert len(expected_logs) == len( actual_logs ), f"Expected {len(expected_logs)} logs, got {len(actual_logs)}" - for expected, actual in zip(expected_logs, actual_logs): assert expected == actual, f"Expected: '{expected}', got: '{actual}'" -def test_min_only(test_data, log_capture): - columns_ranges = { - "pressure": {"min": 150}, +def test_invalid_tag_name(test_data): + tag_ranges = { + "InvalidTagName": {"min": 0, "max": 100}, } - monitor = CheckValueRanges(df=test_data, columns_ranges=columns_ranges) - monitor.check() + with pytest.raises(ValueError) as excinfo: + monitor = CheckValueRanges(df=test_data, tag_ranges=tag_ranges) + monitor.check() - expected_logs = [ - "Found 1 rows in column 'pressure' out of range.", - f"Out of range row in column 'pressure': {test_data.collect()[0]}", - ] + assert "TagName 'InvalidTagName' not found in DataFrame." in str(excinfo.value) - log_contents = log_capture.getvalue() - actual_logs = log_contents.strip().split("\n") - assert len(expected_logs) == len( - actual_logs - ), f"Expected {len(expected_logs)} logs, got {len(actual_logs)}" - for expected, actual in zip(expected_logs, actual_logs): - assert expected == actual, f"Expected: '{expected}', got: '{actual}'" +def test_no_min_or_max(test_data): + tag_ranges = { + "A2PS64V0J.:ZUX09R": {}, # Weder 'min' noch 'max' angegeben + } + with pytest.raises(ValueError) as excinfo: + monitor = CheckValueRanges(df=test_data, tag_ranges=tag_ranges) + monitor.check() + assert ( + "TagName 'A2PS64V0J.:ZUX09R' must have at least 'min' or 'max' specified." + in str(excinfo.value) + ) + +def test_large_dataset(spark, log_capture): + base_path = os.path.dirname(__file__) + file_path = os.path.join(base_path, "../../test_data.csv") + df = spark.read.option("header", "true").csv(file_path) + assert df.count() > 0, "Dataframe was not loaded correct" -def test_max_only(test_data, log_capture): - columns_ranges = { - "humidity": {"max": 90}, + tag_ranges = { + "value_range": {"min": 2, "max": 4, "inclusive_bounds": True}, } - monitor = CheckValueRanges(df=test_data, columns_ranges=columns_ranges) + monitor = CheckValueRanges(df, tag_ranges) monitor.check() expected_logs = [ - "Found 2 rows in column 'humidity' out of range.", - f"Out of range row in column 'humidity': {test_data.collect()[3]}", - f"Out of range row in column 'humidity': {test_data.collect()[4]}", + "Found 2 rows in 'Value' column for TagName 'value_range' out of range.", + f"Out of range row for TagName 'value_range': Row(TagName='value_range', EventTime=datetime.datetime(2024, 1, 2, 3, 49, 45), Status=' Good', Value=1.0)", + f"Out of range row for TagName 'value_range': Row(TagName='value_range', EventTime=datetime.datetime(2024, 1, 2, 20, 3, 46), Status=' Good', Value=5.0)", ] - - log_contents = log_capture.getvalue() - actual_logs = log_contents.strip().split("\n") + actual_logs = log_capture.getvalue().strip().split("\n") assert len(expected_logs) == len( actual_logs ), f"Expected {len(expected_logs)} logs, got {len(actual_logs)}" for expected, actual in zip(expected_logs, actual_logs): - assert expected == actual, f"Expected: '{expected}', got: '{actual}'" - - -def test_invalid_column(test_data): - columns_ranges = { - "invalid_column": {"min": 0, "max": 100}, - } - with pytest.raises(ValueError) as excinfo: - monitor = CheckValueRanges(df=test_data, columns_ranges=columns_ranges) - monitor.check() - assert "Column 'invalid_column' not found in DataFrame." in str(excinfo.value) - - -def test_no_min_or_max(test_data): - columns_ranges = { - "temperature": {}, - } - with pytest.raises(ValueError) as excinfo: - monitor = CheckValueRanges(df=test_data, columns_ranges=columns_ranges) - monitor.check() - assert "Column 'temperature' must have at least 'min' or 'max' specified." in str( - excinfo.value - ) + assert expected in actual, f"Expected: '{expected}', got: '{actual}'" diff --git a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_flatline_detection.py b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_flatline_detection.py index ed5eb688c..af7e6995a 100644 --- a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_flatline_detection.py +++ b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_flatline_detection.py @@ -1,4 +1,5 @@ import pytest +import os from pyspark.sql import SparkSession from src.sdk.python.rtdip_sdk.pipelines.data_quality.monitoring.spark.flatline_detection import ( FlatlineDetection, @@ -34,15 +35,16 @@ def log_capture(): def test_flatline_detection_no_flatlining(spark, log_capture): - data = [ - (1, 5), - (2, 6), - (3, 7), - (4, 8), - (5, 9), - ] - columns = ["ID", "Value"] - df = spark.createDataFrame(data, columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 03:49:45.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 07:53:11.000", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 11:56:42.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 16:00:12.000", "Good", "0.150000006"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 20:03:46.000", "Good", "0.340000004"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) detector = FlatlineDetection(df, watch_columns=["Value"], tolerance_timespan=2) detector.check() @@ -60,23 +62,24 @@ def test_flatline_detection_no_flatlining(spark, log_capture): def test_flatline_detection_with_flatlining(spark, log_capture): - data = [ - (1, 0), - (2, 0), - (3, 0), - (4, 5), - (5, 0), - ] - columns = ["ID", "Value"] - df = spark.createDataFrame(data, columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 03:49:45.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 07:53:11.000", "Good", "0.0"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 11:56:42.000", "Good", "0.0"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 16:00:12.000", "Good", "Null"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 20:03:46.000", "Good", "0.340000004"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) detector = FlatlineDetection(df, watch_columns=["Value"], tolerance_timespan=2) detector.check() expected_logs = [ - "Flatlining detected in column 'Value' at row: Row(ID=1, Value=0).", - "Flatlining detected in column 'Value' at row: Row(ID=2, Value=0).", - "Flatlining detected in column 'Value' at row: Row(ID=3, Value=0).", + "Flatlining detected in column 'Value' at row: Row(TagName='A2PS64V0J.:ZUX09R', EventTime=datetime.datetime(2024, 1, 2, 7, 53, 11), Status='Good', Value=0.0, Value_flatline_flag=1, Value_group=1).", + "Flatlining detected in column 'Value' at row: Row(TagName='A2PS64V0J.:ZUX09R', EventTime=datetime.datetime(2024, 1, 2, 11, 56, 42), Status='Good', Value=0.0, Value_flatline_flag=1, Value_group=1).", + "Flatlining detected in column 'Value' at row: Row(TagName='A2PS64V0J.:ZUX09R', EventTime=datetime.datetime(2024, 1, 2, 16, 0, 12), Status='Good', Value=None, Value_flatline_flag=1, Value_group=1).", ] actual_logs = log_capture.getvalue().strip().split("\n") @@ -87,30 +90,23 @@ def test_flatline_detection_with_flatlining(spark, log_capture): assert expected in actual, f"Expected: '{expected}', got: '{actual}'" -def test_flatline_detection_multiple_columns(spark, log_capture): - data = [ - (1, 0, None), - (2, 0, None), - (3, 0, None), - (4, 1, 1), - (5, 5, 2), - (6, 0, None), - ] - columns = ["ID", "Value1", "Value2"] - df = spark.createDataFrame(data, columns) - - detector = FlatlineDetection( - df, watch_columns=["Value1", "Value2"], tolerance_timespan=2 +def test_flatline_detection_with_tolerance(spark, log_capture): + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 03:49:45.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 07:53:11.000", "Good", "0.0"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 11:56:42.000", "Good", "0.0"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 16:00:12.000", "Good", "Null"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 20:03:46.000", "Good", "0.340000004"), + ], + ["TagName", "EventTime", "Status", "Value"], ) + + detector = FlatlineDetection(df, watch_columns=["Value"], tolerance_timespan=3) detector.check() expected_logs = [ - "Flatlining detected in column 'Value1' at row: Row(ID=1, Value1=0, Value2=None).", - "Flatlining detected in column 'Value1' at row: Row(ID=2, Value1=0, Value2=None).", - "Flatlining detected in column 'Value1' at row: Row(ID=3, Value1=0, Value2=None).", - "Flatlining detected in column 'Value2' at row: Row(ID=1, Value1=0, Value2=None).", - "Flatlining detected in column 'Value2' at row: Row(ID=2, Value1=0, Value2=None).", - "Flatlining detected in column 'Value2' at row: Row(ID=3, Value1=0, Value2=None).", + "No flatlining detected in column 'Value'.", ] actual_logs = log_capture.getvalue().strip().split("\n") @@ -121,23 +117,21 @@ def test_flatline_detection_multiple_columns(spark, log_capture): assert expected in actual, f"Expected: '{expected}', got: '{actual}'" -def test_flatline_detection_with_tolerance(spark, log_capture): - data = [ - (1, 0), - (2, 0), - (3, 5), - (4, 0), - (5, 0), - (6, 0), - ] - columns = ["ID", "Value"] - df = spark.createDataFrame(data, columns) +def test_large_dataset(spark, log_capture): + base_path = os.path.dirname(__file__) + file_path = os.path.join(base_path, "../../test_data.csv") + df = spark.read.option("header", "true").csv(file_path) - detector = FlatlineDetection(df, watch_columns=["Value"], tolerance_timespan=3) + print(df.count) + assert df.count() > 0, "Dataframe was not loaded correct" + + detector = FlatlineDetection(df, watch_columns=["Value"], tolerance_timespan=2) detector.check() expected_logs = [ - "No flatlining detected in column 'Value'.", + "Flatlining detected in column 'Value' at row: Row(TagName='FLATLINE_TEST', EventTime=datetime.datetime(2024, 1, 2, 2, 35, 10, 511000), Status='Good', Value=0.0, Value_flatline_flag=1, Value_group=1).", + "Flatlining detected in column 'Value' at row: Row(TagName='FLATLINE_TEST', EventTime=datetime.datetime(2024, 1, 2, 2, 49, 10, 408000), Status='Good', Value=0.0, Value_flatline_flag=1, Value_group=1).", + "Flatlining detected in column 'Value' at row: Row(TagName='FLATLINE_TEST', EventTime=datetime.datetime(2024, 1, 2, 14, 57, 10, 372000), Status='Good', Value=0.0, Value_flatline_flag=1, Value_group=1).", ] actual_logs = log_capture.getvalue().strip().split("\n") diff --git a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_interval.py b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_interval.py index 4a5cff94b..c96767f09 100644 --- a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_interval.py +++ b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_interval.py @@ -1,4 +1,5 @@ import pytest +import os from pyspark.sql import SparkSession from src.sdk.python.rtdip_sdk.pipelines.logging.logger_manager import LoggerManager @@ -36,21 +37,33 @@ def log_capture(): handler.close() -def test_missing_intervals_with_given_interval(spark, caplog): - data = [ - (1, "2024-02-11 00:00:00.000"), - (2, "2024-02-11 00:00:10.000"), - (3, "2024-02-11 00:00:20.000"), - (4, "2024-02-11 00:00:36.000"), # Missing interval (20s to 36s) - (5, "2024-02-11 00:00:45.000"), - (6, "2024-02-11 00:00:55.000"), - (7, "2024-02-11 00:01:05.000"), - (8, "2024-02-11 00:01:15.000"), - (9, "2024-02-11 00:01:25.000"), - (10, "2024-02-11 00:01:41.000"), # Missing interval (25s to 41s) - ] - columns = ["Index", "EventTime"] - df = spark.createDataFrame(data, schema=columns) +def test_missing_intervals_with_given_interval_multiple_tags(spark, caplog): + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:00.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:10.000", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:20.000", "Good", "0.129999995"), + ( + "A2PS64V0J.:ZUX09R", + "2024-01-02 00:00:36.000", + "Good", + "0.150000006", + ), # Missing interval (20s to 36s) + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:45.000", "Good", "0.340000004"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:55.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:05.000", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:15.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:25.000", "Good", "0.150000006"), + ( + "A2PS64V0J.:ZUX09R", + "2024-01-02 00:01:41.000", + "Good", + "0.340000004", + ), # Missing interval (25s to 41s) + ], + ["TagName", "EventTime", "Status", "Value"], + ) + monitor = IdentifyMissingDataInterval( df=df, interval="10s", @@ -64,8 +77,8 @@ def test_missing_intervals_with_given_interval(spark, caplog): "Using provided tolerance: 500.0 ms", "Maximum acceptable interval with tolerance: 10500.0 ms", "Detected Missing Intervals:", - "Missing Interval from 2024-02-11 00:00:20 to 2024-02-11 00:00:36 Duration: 0h 0m 16s", - "Missing Interval from 2024-02-11 00:01:25 to 2024-02-11 00:01:41 Duration: 0h 0m 16s", + "Tag: A2PS64V0J.:ZUX09R Missing Interval from 2024-01-02 00:00:20 to 2024-01-02 00:00:36 Duration: 0h 0m 16s", + "Tag: A2PS64V0J.:ZUX09R Missing Interval from 2024-01-02 00:01:25 to 2024-01-02 00:01:41 Duration: 0h 0m 16s", ] actual_logs = [ record.message @@ -81,20 +94,27 @@ def test_missing_intervals_with_given_interval(spark, caplog): def test_missing_intervals_with_calculated_interval(spark, caplog): - data = [ - (1, "2024-02-11 00:00:00.000"), - (2, "2024-02-11 00:00:10.000"), - (3, "2024-02-11 00:00:20.000"), - (4, "2024-02-11 00:00:36.000"), # Missing interval (20s to 36s) - (5, "2024-02-11 00:00:45.000"), - (6, "2024-02-11 00:00:55.000"), - (7, "2024-02-11 00:01:05.000"), - (8, "2024-02-11 00:01:15.000"), - (9, "2024-02-11 00:01:25.000"), - (10, "2024-02-11 00:01:30.000"), - ] - columns = ["Index", "EventTime"] - df = spark.createDataFrame(data, schema=columns) + + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:00.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:10.000", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:20.000", "Good", "0.129999995"), + ( + "A2PS64V0J.:ZUX09R", + "2024-01-02 00:00:36.000", + "Good", + "0.150000006", + ), # Missing interval (20s to 36s) + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:45.000", "Good", "0.340000004"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:55.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:05.000", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:15.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:25.000", "Good", "0.150000006"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:30.000", "Good", "0.340000004"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) monitor = IdentifyMissingDataInterval( df=df, ) @@ -106,7 +126,7 @@ def test_missing_intervals_with_calculated_interval(spark, caplog): "Calculated tolerance: 10.0 ms (MAD-based)", "Maximum acceptable interval with tolerance: 10010.0 ms", "Detected Missing Intervals:", - "Missing Interval from 2024-02-11 00:00:20 to 2024-02-11 00:00:36 Duration: 0h 0m 16s", + "Tag: A2PS64V0J.:ZUX09R Missing Interval from 2024-01-02 00:00:20 to 2024-01-02 00:00:36 Duration: 0h 0m 16s", ] actual_logs = [ record.message @@ -122,20 +142,22 @@ def test_missing_intervals_with_calculated_interval(spark, caplog): def test_no_missing_intervals(spark, caplog): - data = [ - (1, "2024-02-11 00:00:00.000"), - (2, "2024-02-11 00:00:10.000"), - (3, "2024-02-11 00:00:20.000"), - (4, "2024-02-11 00:00:30.000"), - (5, "2024-02-11 00:00:40.000"), - (6, "2024-02-11 00:00:50.000"), - (7, "2024-02-11 00:01:00.000"), - (8, "2024-02-11 00:01:10.000"), - (9, "2024-02-11 00:01:20.000"), - (10, "2024-02-11 00:01:30.000"), - ] - columns = ["Index", "EventTime"] - df = spark.createDataFrame(data, schema=columns) + + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:00.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:10.000", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:20.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:30.000", "Good", "0.150000006"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:40.000", "Good", "0.340000004"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:50.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:00.000", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:10.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:20.000", "Good", "0.150000006"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:30.000", "Good", "0.340000004"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) monitor = IdentifyMissingDataInterval( df=df, interval="10s", @@ -164,12 +186,13 @@ def test_no_missing_intervals(spark, caplog): def test_invalid_timedelta_format(spark, caplog): - data = [ - (1, "2024-02-11 00:00:00.000"), - (2, "2024-02-11 00:00:10.000"), - ] - columns = ["Index", "EventTime"] - df = spark.createDataFrame(data, schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 16:00:12.000", "Good", "0.150000006"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 20:03:46.000", "Good", "0.340000004"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) monitor = IdentifyMissingDataInterval( df=df, interval="10seconds", # should be '10s' @@ -181,3 +204,31 @@ def test_invalid_timedelta_format(spark, caplog): assert "Invalid time format: 10seconds" in str(exc_info.value) assert "Invalid time format: 10seconds" in caplog.text + + +def test_large_data_set(spark, caplog): + base_path = os.path.dirname(__file__) + file_path = os.path.join(base_path, "../../test_data.csv") + df = spark.read.option("header", "true").csv(file_path) + assert df.count() > 0, "Dataframe was not loaded correct" + monitor = IdentifyMissingDataInterval( + df=df, + interval="1s", + tolerance="10ms", + ) + with caplog.at_level(logging.INFO, logger="IdentifyMissingDataInterval"): + monitor.check() + expected_logs = [ + "Tag: MISSING_DATA Missing Interval from 2024-01-02 00:08:11 to 2024-01-02 00:08:13 Duration: 0h 0m 2s" + ] + actual_logs = [ + record.message + for record in caplog.records + if record.levelname == "INFO" + and record.name == "IdentifyMissingDataInterval" + and "MISSING_DATA" in record.message + ] + + assert any( + expected in actual for expected in expected_logs for actual in actual_logs + ), "Expected logs not found in actual logs" diff --git a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_pattern.py b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_pattern.py index b761db3b7..14306d391 100644 --- a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_pattern.py +++ b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/monitoring/spark/test_identify_missing_data_pattern.py @@ -2,10 +2,9 @@ import pytest import logging +import os from pyspark.sql import SparkSession -from pyspark.sql import Row -from pyspark.sql.types import StructType, StructField, StringType from src.sdk.python.rtdip_sdk.pipelines.data_quality.monitoring.spark.identify_missing_data_pattern import ( IdentifyMissingDataPattern, @@ -25,16 +24,17 @@ def spark(): def test_no_missing_patterns(spark, caplog): - data = [ - ("2024-02-11 00:00:00",), - ("2024-02-11 00:00:13",), - ("2024-02-11 00:00:49",), - ("2024-02-11 00:01:00",), - ("2024-02-11 00:01:13",), - ("2024-02-11 00:01:49",), - ] - columns = ["EventTime"] - df = spark.createDataFrame([Row(*row) for row in data], schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:00", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:13", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:49", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:00", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:13", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:49", "Good", "0.129999995"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) patterns = [{"second": 0}, {"second": 13}, {"second": 49}] monitor = IdentifyMissingDataPattern( df=df, patterns=patterns, frequency="minutely", tolerance="1s" @@ -54,16 +54,21 @@ def test_no_missing_patterns(spark, caplog): def test_some_missing_patterns(spark, caplog): - data = [ - ("2024-02-11 00:00:00",), - ("2024-02-11 00:00:13",), - ("2024-02-11 00:00:49",), - # Nothing matches in minute 1 - ("2024-02-11 00:01:05",), - ("2024-02-11 00:01:17",), - ] - columns = ["EventTime"] - df = spark.createDataFrame([Row(*row) for row in data], schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:00", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:13", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:49", "Good", "0.129999995"), + ( + "A2PS64V0J.:ZUX09R", + "2024-02-11 00:01:05", + "Good", + "0.129999995", + ), # Nothing matches in minute 1 + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:17", "Good", "0.119999997"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) patterns = [{"second": 0}, {"second": 13}, {"second": 49}] monitor = IdentifyMissingDataPattern( df=df, patterns=patterns, frequency="minutely", tolerance="1s" @@ -85,16 +90,23 @@ def test_some_missing_patterns(spark, caplog): def test_all_missing_patterns(spark, caplog): - data = [ - ("2024-02-11 00:00:05",), - ("2024-02-11 00:00:17",), - ("2024-02-11 00:00:29",), - ("2024-02-11 00:01:05",), - ("2024-02-11 00:01:17",), - ("2024-02-11 00:01:29",), - ] - columns = ["EventTime"] - df = spark.createDataFrame([Row(*row) for row in data], schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:05", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:17", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:29", "Good", "0.129999995"), + ( + "A2PS64V0J.:ZUX09R", + "2024-02-11 00:01:05", + "Good", + "0.129999995", + ), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:17", "Good", "0.119999997"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:29", "Good", "0.129999995"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) + patterns = [{"second": 0}, {"second": 13}, {"second": 49}] monitor = IdentifyMissingDataPattern( df=df, patterns=patterns, frequency="minutely", tolerance="1s" @@ -122,42 +134,16 @@ def test_all_missing_patterns(spark, caplog): assert pattern in actual_logs -def test_empty_dataframe(spark, caplog): - schema = StructType([StructField("EventTime", StringType(), True)]) - df = spark.createDataFrame([], schema=schema) - patterns = [{"second": 0}, {"second": 13}, {"second": 49}] - monitor = IdentifyMissingDataPattern( - df=df, patterns=patterns, frequency="minutely", tolerance="1s" - ) - - with caplog.at_level(logging.INFO, logger="IdentifyMissingDataPattern"): - monitor.check() - - actual_logs = [ - record.message - for record in caplog.records - if record.levelname == "INFO" and record.name == "IdentifyMissingDataPattern" - ] - assert "Using tolerance: 1000.0 ms (1.0 seconds)" in actual_logs - assert "DataFrame is empty. No missing patterns to detect." in actual_logs - - def test_invalid_patterns(spark, caplog): - """ - Testet den Fall, in dem die bereitgestellten Muster ungültig sind. - """ - # Beispiel-Daten - data = [ - ("2024-02-11 00:00:00",), - ("2024-02-11 00:00:13",), - ("2024-02-11 00:00:49",), - ] - columns = ["EventTime"] - df = spark.createDataFrame([Row(*row) for row in data], schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:49", "Good", "0.129999995"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) - # Definiere ungültige Muster (fehlender 'second' Schlüssel) patterns = [ - {"minute": 0}, # Ungültig für 'minutely' Frequenz + {"minute": 0}, # Invalid for 'minutely' frequency {"second": 13}, {"second": 49}, ] @@ -176,13 +162,12 @@ def test_invalid_patterns(spark, caplog): def test_invalid_tolerance_format(spark, caplog): - data = [ - ("2024-02-11 00:00:00",), - ("2024-02-11 00:00:13",), - ("2024-02-11 00:00:49",), - ] - columns = ["EventTime"] - df = spark.createDataFrame([Row(*row) for row in data], schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:01:49", "Good", "0.129999995"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) patterns = [{"second": 0}, {"second": 13}, {"second": 49}] monitor = IdentifyMissingDataPattern( df=df, patterns=patterns, frequency="minutely", tolerance="1minute" @@ -203,13 +188,15 @@ def test_invalid_tolerance_format(spark, caplog): def test_hourly_patterns_with_microseconds(spark, caplog): - data = [ - ("2024-02-11 00:00:00.200",), - ("2024-02-11 00:59:59.800",), - ("2024-02-11 01:00:30.500",), - ] - columns = ["EventTime"] - df = spark.createDataFrame([Row(*row) for row in data], schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:00:00.200", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 00:59:59.800", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-02-11 01:00:30.500", "Good", "0.129999995"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) + patterns = [ {"minute": 0, "second": 0, "millisecond": 0}, {"minute": 30, "second": 30, "millisecond": 500}, @@ -230,3 +217,15 @@ def test_hourly_patterns_with_microseconds(spark, caplog): assert "Identified 1 missing patterns." in actual_logs assert "Detected Missing Patterns:" in actual_logs assert "Missing Pattern at 2024-02-11 00:30:30.500" in actual_logs + + +def test_large_data_set(spark): + base_path = os.path.dirname(__file__) + file_path = os.path.join(base_path, "../../test_data.csv") + df = spark.read.option("header", "true").csv(file_path) + assert df.count() > 0, "Dataframe was not loaded correct" + patterns = [{"second": 0}, {"second": 13}, {"second": 49}] + monitor = IdentifyMissingDataPattern( + df=df, patterns=patterns, frequency="minutely", tolerance="1s" + ) + monitor.check() diff --git a/tests/sdk/python/rtdip_sdk/pipelines/data_quality/test_data.csv b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/test_data.csv new file mode 100644 index 000000000..d99d3e323 --- /dev/null +++ b/tests/sdk/python/rtdip_sdk/pipelines/data_quality/test_data.csv @@ -0,0 +1,1015 @@ +TagName,EventTime,Status,Value +A2PS64V0J.:ZUX09R,2024-01-02 20:03:46.000,Good,0.3400000035762787 +A2PS64V0J.:ZUX09R,2024-01-02 16:00:12.000,Good,0.1500000059604644 +A2PS64V0J.:ZUX09R,2024-01-02 11:56:42.000,Good,0.1299999952316284 +A2PS64V0J.:ZUX09R,2024-01-02 07:53:11.000,Good,0.1199999973177909 +A2PS64V0J.:ZUX09R,2024-01-02 03:49:45.000,Good,0.1299999952316284 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 20:09:58.053,Good,7107.82080078125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:27:10.518,Good,19407.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 05:23:10.143,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:31:10.086,Good,19399.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:41:10.358,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 18:09:10.488,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:15:10.492,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 06:51:10.077,Good,19403.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 07:42:24.227,Good,6.55859375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:08:23.777,Good,5921.5498046875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 05:14:10.896,Good,5838.216796875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 01:37:10.967,Good,5607.82568359375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 00:26:53.449,Good,5563.7080078125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:11:10.361,Good,19396.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:01:10.150,Good,19409.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 10:22:10.018,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:58:10.496,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 06:50:10.483,Good,19402.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 07:26:20.495,Good,6.55126953125 +R0:Z24WVP.0S10L,2024-01-02 21:26:00.001,Good,2266.861083984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:16:08.988,Good,7205.85986328125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 14:25:10.252,Good,19410.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 07:18:10.275,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:12:10.288,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:04:10.256,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 03:16:10.178,Good,19401.0 +R0:Z24WVP.0S10L,2024-01-02 16:21:00.001,Good,2267.4541015625 +R0:Z24WVP.0S10L,2024-01-02 10:28:01.001,Good,2344.558349609375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 07:23:40.514,Good,6132.33349609375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:34:57.886,Good,5818.609375 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:45:10.416,Good,19371.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:35:10.108,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:22:10.381,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 01:08:10.214,Good,19396.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:57:10.083,Good,19397.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:44:10.054,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:57:10.201,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:38:10.450,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:13:10.477,Good,19385.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 09:12:10.466,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 08:22:10.145,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 06:42:10.099,Good,19404.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 17:12:09.997,Good,6867.62548828125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:54:59.922,Good,6249.98046875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:45:10.238,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:52:10.381,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:37:10.213,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:13:10.226,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:43:10.096,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 21:08:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 04:44:01.001,Good,2307.78564453125 +R0:Z24WVP.0S10L,2024-01-02 03:38:00.001,Good,2306.006103515625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 05:30:10.341,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:06:10.475,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:36:10.389,Good,19410.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:01:10.231,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 03:20:10.309,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:52:10.136,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:08:10.000,Good,19395.0 +R0:Z24WVP.0S10L,2024-01-02 22:40:00.001,Good,2300.074951171875 +R0:Z24WVP.0S10L,2024-01-02 10:22:00.001,Good,2346.9306640625 +PM20:PCO4SLU_000R4.3D0_T-23,2024-01-02 23:39:20.058,Good,5.300000190734863 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 14:35:31.661,Good,6514.685546875 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:34:10.228,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:39:10.043,Good,19375.0 +R0:Z24WVP.0S10L,2024-01-02 20:02:00.000,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 01:45:01.001,Good,2304.81982421875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:38:10.472,Good,19406.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 07:19:10.316,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:28:10.208,Good,19399.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:12:10.481,Good,19395.0 +R0:Z24WVP.0S10L,2024-01-02 18:54:00.001,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 19:48:56.048,Good,7073.50732421875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:38:10.214,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:06:10.336,Good,19405.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:19:10.497,Good,19399.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:35:10.480,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:44:10.247,Good,19380.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 15:42:10.046,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:40:10.497,Good,19397.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 09:47:55.430,Good,6.615234375 +R0:Z24WVP.0S10L,2024-01-02 12:36:00.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:41:15.646,Good,7240.17333984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 19:23:42.152,Good,7034.29150390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:31:30.460,Good,5975.47119140625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:48:10.347,Good,19373.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:32:10.261,Good,19399.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:14:10.435,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:30:10.228,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 06:54:10.356,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 23:47:00.001,Good,2258.5576171875 +R0:Z24WVP.0S10L,2024-01-02 23:05:00.001,Good,2298.88916015625 +R0:Z24WVP.0S10L,2024-01-02 18:39:00.001,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 07:03:36.141,Good,6068.6083984375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:33:10.113,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:40:10.232,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:47:10.467,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:50:10.087,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:59:10.357,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:04:10.452,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:05:10.307,Good,19394.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:03:10.279,Good,19395.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:11:10.407,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 14:25:00.001,Good,2265.081787109375 +R0:Z24WVP.0S10L,2024-01-02 01:17:00.001,Good,2306.006103515625 +1N325T3MTOR-P0L29:9.T0,2024-01-02 13:23:10.098,Good,19409.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:31:10.337,Good,19411.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:05:10.479,Good,19396.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 04:22:36.151,Good,6.43603515625 +R0:Z24WVP.0S10L,2024-01-02 19:30:00.014,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 07:22:00.001,Good,2310.158203125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 22:43:28.441,Good,7284.291015625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:33:10.245,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:24:10.199,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:54:10.428,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 07:34:10.156,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:13:10.270,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:33:10.295,Good,19397.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 18:40:10.232,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 09:39:10.294,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 08:36:10.294,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:18:10.275,Good,19404.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 16:47:04.123,Good,6848.017578125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:05:22.981,Good,5906.84423828125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:22:10.076,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 13:34:10.499,Good,19408.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:46:10.139,Good,19377.0 +R0:Z24WVP.0S10L,2024-01-02 12:53:00.001,Good,2265.6748046875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 01:25:06.919,Good,5588.2177734375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:02:10.354,Good,19373.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:28:10.325,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:48:10.122,Good,19396.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:53:10.049,Good,19405.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:34:10.389,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:19:10.174,Good,19376.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 04:35:39.227,Good,6.4423828125 +R0:Z24WVP.0S10L,2024-01-02 14:45:00.001,Good,2266.26806640625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:42:10.034,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:07:10.035,Good,19380.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:15:10.449,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:48:10.347,Good,19373.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:11:10.376,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 13:46:10.091,Good,19409.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:55:10.339,Good,19404.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 03:38:44.198,Good,5705.8642578125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:21:10.452,Good,19379.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 19:20:10.382,Good,19379.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 16:10:10.095,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 14:35:10.297,Good,19410.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:42:10.486,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:32:10.169,Good,19395.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:04:10.068,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 04:32:10.413,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:14:10.274,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 01:54:10.132,Good,19399.0 +R0:Z24WVP.0S10L,2024-01-02 20:54:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 02:02:00.001,Good,2304.81982421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 14:48:34.105,Good,6534.29345703125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:57:10.117,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:15:10.393,Good,19410.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:35:10.215,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:16:10.070,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:01:10.497,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:38:10.380,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:25:10.428,Good,19375.0 +R0:Z24WVP.0S10L,2024-01-02 14:54:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 12:15:00.001,Good,2264.488525390625 +R0:Z24WVP.0S10L,2024-01-02 09:36:00.001,Good,2312.53076171875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:24:27.269,Good,5960.765625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:30:56.563,Good,5818.609375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:17:10.113,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:19:10.348,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 05:39:10.120,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:35:10.483,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:17:10.113,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:52:10.264,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:58:10.031,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:21:10.383,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:55:10.264,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 19:10:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 10:38:00.001,Good,2347.52392578125 +R0:Z24WVP.0S10L,2024-01-02 01:16:01.001,Good,2305.413330078125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:25:10.042,Good,19396.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:11:10.233,Good,19379.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:36:10.463,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:51:10.216,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:25:10.252,Good,19410.0 +R0:Z24WVP.0S10L,2024-01-02 18:04:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 14:48:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 02:26:01.001,Good,2304.81982421875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:45:10.147,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 14:37:10.404,Good,19411.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 20:50:10.027,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:08:10.248,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:53:10.249,Good,19372.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 12:46:10.520,Good,19409.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 13:57:10.389,Good,19409.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:57:10.430,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 20:12:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 14:46:01.001,Good,2266.861083984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:46:50.909,Good,6700.95947265625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 14:40:32.055,Good,6519.58740234375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 12:12:52.261,Good,6362.72509765625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 05:04:07.396,Good,5828.4130859375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:02:10.417,Good,19405.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 11:48:10.231,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:10:10.055,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:22:10.379,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:05:10.279,Good,19376.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:18:49.267,Good,6.4658203125 +R0:Z24WVP.0S10L,2024-01-02 01:43:00.001,Good,2304.81982421875 +R0:Z24WVP.0S10L,2024-01-02 01:03:00.001,Good,2304.81982421875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:30:10.122,Good,19380.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:16:10.297,Good,19383.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:24:10.132,Good,19401.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:21:10.191,Good,19396.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:00:10.325,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:26:10.116,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:16:10.199,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 13:54:10.106,Good,19409.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 19:15:12.284,Good,6.810546875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:51:10.379,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:41:10.504,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:24:10.265,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:50:10.432,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:33:10.389,Good,19375.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 10:09:00.796,Good,6.625 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:15:48.607,Good,6.46435546875 +R0:Z24WVP.0S10L,2024-01-02 21:47:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 12:44:00.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:17:51.642,Good,6205.86279296875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:57:10.201,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:25:10.157,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:39:10.378,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:18:10.423,Good,19398.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:25:10.262,Good,19380.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 07:22:10.465,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 23:00:00.001,Good,2296.5166015625 +R0:Z24WVP.0S10L,2024-01-02 05:50:00.001,Good,2308.378662109375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:20:10.029,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:56:10.024,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:31:10.152,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:13:10.406,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 12:35:10.110,Good,19406.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 03:47:10.341,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 10:45:00.001,Good,2263.8955078125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:38:10.281,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:53:10.052,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 13:10:10.491,Good,19408.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 07:51:10.090,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:05:10.291,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 09:54:10.181,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 03:59:10.079,Good,19402.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 06:19:03.191,Good,6.515625 +R0:Z24WVP.0S10L,2024-01-02 18:52:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 17:57:00.001,Good,2267.4541015625 +R0:Z24WVP.0S10L,2024-01-02 14:43:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 03:31:01.001,Good,2306.006103515625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:49:17.685,Good,7249.97705078125 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:57:10.292,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 15:36:10.106,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:38:10.212,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:25:10.262,Good,19380.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:39:10.032,Good,19373.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:50:10.168,Good,19396.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:11:47.514,Good,6.46142578125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:25:45.091,Good,6656.841796875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:40:10.199,Good,19406.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:30:10.243,Good,19410.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 13:24:10.225,Good,19408.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:45:10.330,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:05:10.348,Good,19399.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 06:44:09.960,Good,6.53076171875 +R0:Z24WVP.0S10L,2024-01-02 19:43:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 11:43:01.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 05:52:00.001,Good,2308.378662109375 +R0:Z24WVP.0S10L,2024-01-02 00:53:00.001,Good,2305.413330078125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:55:19.247,Good,7254.87939453125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:37:10.382,Good,19373.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 13:13:10.228,Good,19410.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:56:10.434,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:58:10.254,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:45:10.464,Good,19376.0 +R0:Z24WVP.0S10L,2024-01-02 13:07:00.001,Good,2264.488525390625 +R0:Z24WVP.0S10L,2024-01-02 12:38:00.001,Good,2265.081787109375 +R0:Z24WVP.0S10L,2024-01-02 10:32:00.001,Good,2346.9306640625 +R0:Z24WVP.0S10L,2024-01-02 07:45:00.001,Good,2310.158203125 +R0:Z24WVP.0S10L,2024-01-02 02:42:00.001,Good,2304.81982421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:38:57.109,Good,6220.56884765625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:22:10.184,Good,19374.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:08:10.394,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:24:10.385,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:56:10.343,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 01:21:10.136,Good,19398.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 00:41:43.646,Good,6.39013671875 +R0:Z24WVP.0S10L,2024-01-02 03:55:00.001,Good,2306.006103515625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 09:10:04.230,Good,6245.07861328125 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:36:10.430,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:28:10.059,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 12:21:10.044,Good,19406.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:18:10.500,Good,19396.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 09:18:10.258,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 08:38:00.002,Good,2311.344482421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 17:32:14.792,Good,6892.13525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 05:30:14.921,Good,5843.119140625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:11:10.233,Good,19379.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:06:10.388,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:10:10.302,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:25:10.032,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:45:10.419,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:17:10.151,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:22:10.018,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:09:10.247,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 23:40:00.001,Good,2301.8544921875 +R0:Z24WVP.0S10L,2024-01-02 13:45:00.001,Good,2265.081787109375 +R0:Z24WVP.0S10L,2024-01-02 07:19:00.001,Good,2310.158203125 +R0:Z24WVP.0S10L,2024-01-02 02:41:00.001,Good,2305.413330078125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:29:46.609,Good,6676.44970703125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:33:57.828,Good,5823.51123046875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:21:10.464,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:49:10.165,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:04:10.313,Good,19379.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 15:22:10.304,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:36:10.389,Good,19410.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 04:05:10.365,Good,19403.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:56:57.891,Good,6.5009765625 +R0:Z24WVP.0S10L,2024-01-02 16:49:00.001,Good,2267.4541015625 +R0:Z24WVP.0S10L,2024-01-02 15:38:00.001,Good,2266.861083984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:51:18.376,Good,7245.0751953125 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:23:10.093,Good,19379.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:22:10.398,Good,19410.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:05:10.327,Good,19409.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 18:53:10.249,Good,19372.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 12:07:10.458,Good,19406.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:35:10.184,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 21:43:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 14:42:01.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 00:44:00.001,Good,2304.81982421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 10:09:19.567,Good,6274.490234375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:41:10.441,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:37:09.997,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:11:10.120,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:33:10.374,Good,19402.0 +R0:Z24WVP.0S10L,2024-01-02 23:45:00.001,Good,2275.7578125 +R0:Z24WVP.0S10L,2024-01-02 05:58:00.001,Good,2309.56494140625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:37:10.172,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 07:02:10.081,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:42:10.034,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 12:50:10.139,Good,19408.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:17:10.123,Good,19403.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:55:57.659,Good,6.49951171875 +R0:Z24WVP.0S10L,2024-01-02 23:37:00.001,Good,2300.074951171875 +R0:Z24WVP.0S10L,2024-01-02 02:54:00.001,Good,2306.006103515625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 09:18:05.695,Good,6259.7841796875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:21:10.276,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:32:10.219,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:37:10.431,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:41:10.450,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:42:10.486,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:51:10.029,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 18:02:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 10:17:00.001,Good,2344.558349609375 +R0:Z24WVP.0S10L,2024-01-02 06:03:00.001,Good,2309.56494140625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:53:59.739,Good,6245.07861328125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:19:26.112,Good,5941.15771484375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 13:27:10.473,Good,19409.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:50:10.257,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:05:10.021,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:37:10.214,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:20:10.142,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:17:10.062,Good,19410.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 04:11:10.500,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 17:24:00.001,Good,2267.4541015625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:29:30.287,Good,5970.5693359375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 13:44:10.013,Good,19409.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:29:10.029,Good,19401.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:08:10.053,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:47:10.271,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:23:10.068,Good,19411.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 10:45:10.004,Good,19403.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 20:26:59.616,Good,7122.52685546875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:34:10.422,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:20:10.225,Good,19401.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:51:10.236,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:59:10.286,Good,19403.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 21:33:46.754,Good,6.81005859375 +R0:Z24WVP.0S10L,2024-01-02 18:51:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 14:06:01.001,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:18:54.746,Good,5794.099609375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 05:25:10.303,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:37:10.348,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:30:10.125,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:21:10.432,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:07:10.491,Good,19400.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:52:10.285,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 04:13:10.194,Good,19403.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 09:39:52.993,Good,6.61083984375 +R0:Z24WVP.0S10L,2024-01-02 14:36:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 10:24:00.001,Good,2342.779052734375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:27:56.333,Good,5818.609375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:40:10.365,Good,19379.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:29:10.405,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 13:54:10.106,Good,19409.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 07:36:10.230,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:08:10.070,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:46:10.068,Good,19411.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 06:19:10.348,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:38:10.325,Good,19396.0 +R0:Z24WVP.0S10L,2024-01-02 13:15:00.001,Good,2264.488525390625 +R0:Z24WVP.0S10L,2024-01-02 09:49:00.001,Good,2345.151611328125 +R0:Z24WVP.0S10L,2024-01-02 06:30:00.001,Good,2308.971923828125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 18:50:34.408,Good,6990.17431640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 01:34:09.551,Good,5607.82568359375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 19:53:10.261,Good,19373.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:41:10.106,Good,19396.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 12:17:53.443,Good,6377.43115234375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:43:10.331,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:42:10.046,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:28:10.514,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:47:10.305,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:24:10.180,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 12:42:10.399,Good,19408.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:09:10.224,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:30:10.074,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:53:10.081,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 21:40:01.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 02:05:00.001,Good,2304.81982421875 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:38:10.214,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 18:46:10.111,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 09:58:10.127,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:51:10.090,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:28:10.082,Good,19405.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 22:49:04.742,Good,6.79833984375 +R0:Z24WVP.0S10L,2024-01-02 07:17:00.001,Good,2310.158203125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:40:31.323,Good,6009.78515625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:00:49.864,Good,5759.78564453125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:55:10.104,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 19:49:10.315,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:07:10.167,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:47:10.469,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:53:10.240,Good,19402.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 17:55:53.258,Good,6.7783203125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 20:05:57.805,Good,7098.01708984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 13:47:18.272,Good,6455.8623046875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:17:54.710,Good,5808.80517578125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:30:10.082,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:11:10.145,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 14:10:10.123,Good,19410.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:46:10.198,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:34:10.017,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:44:10.292,Good,19396.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 18:04:55.376,Good,6.78125 +R0:Z24WVP.0S10L,2024-01-02 16:13:00.001,Good,2267.4541015625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 14:18:26.463,Good,6490.17578125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:22:55.937,Good,5818.609375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 13:34:10.499,Good,19408.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:14:10.381,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:07:10.462,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:53:10.115,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:33:10.229,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:13:10.494,Good,19369.0 +R0:Z24WVP.0S10L,2024-01-02 19:03:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 15:36:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 05:36:00.001,Good,2307.78564453125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 01:36:10.902,Good,5602.92333984375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:42:10.070,Good,19380.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:41:10.146,Good,19407.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 15:29:09.995,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:01:10.012,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:44:10.161,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:43:10.184,Good,19396.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:04:10.483,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 06:29:10.405,Good,19404.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:13:48.079,Good,6.462890625 +R0:Z24WVP.0S10L,2024-01-02 19:25:01.005,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 13:26:00.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 11:37:43.098,Good,6323.509765625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:40:59.941,Good,5823.51123046875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:46:10.520,Good,19409.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:47:10.175,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:15:10.369,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:55:10.308,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:06:10.388,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:06:10.090,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:54:10.133,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:34:10.156,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 08:20:00.001,Good,2310.751220703125 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:38:10.521,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:31:10.184,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:33:10.264,Good,19378.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 07:39:23.513,Good,6.55712890625 +R0:Z24WVP.0S10L,2024-01-02 22:10:00.004,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 23:39:42.178,Good,7338.21240234375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 07:41:10.491,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:26:10.264,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:20:10.015,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:48:10.322,Good,19405.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 04:48:42.149,Good,6.4482421875 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 02:48:10.555,Good,6.40771484375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 20:35:00.708,Good,7147.03662109375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 19:19:41.408,Good,7039.19384765625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:04:50.985,Good,5774.49169921875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:13:10.358,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:10:10.359,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:52:10.501,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:26:10.299,Good,19411.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 12:18:10.305,Good,19406.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:03:10.098,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:55:10.207,Good,19380.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:32:10.250,Good,19402.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 23:38:41.723,Good,7333.310546875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:38:10.521,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:30:10.074,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:48:10.312,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:38:10.185,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:33:10.109,Good,19405.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 08:56:41.384,Good,6.59033203125 +R0:Z24WVP.0S10L,2024-01-02 06:20:00.000,Good,2308.971923828125 +R0:Z24WVP.0S10L,2024-01-02 01:26:00.001,Good,2305.413330078125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 05:36:16.042,Good,5857.82470703125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:53:03.575,Good,5828.4130859375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:20:10.430,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 11:53:10.049,Good,19405.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:17:10.042,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:15:10.160,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:08:10.042,Good,19400.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:46:10.373,Good,19379.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:57:10.475,Good,19405.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 18:42:10.287,Good,19375.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 10:01:59.016,Good,6.62158203125 +R0:Z24WVP.0S10L,2024-01-02 15:28:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 15:17:01.001,Good,2266.861083984375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:34:10.228,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:17:10.443,Good,19382.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 13:58:10.441,Good,19410.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:14:10.029,Good,19403.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:01:21.345,Good,5906.84423828125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 19:54:10.321,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:50:10.468,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:13:10.367,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:14:10.095,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:15:10.427,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 16:11:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 10:42:00.001,Good,2317.86865234375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 12:34:57.359,Good,6401.94091796875 +1N325T3MTOR-P0L29:9.T0,2024-01-02 01:17:10.377,Good,19399.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:26:10.455,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 17:03:00.001,Good,2267.4541015625 +R0:Z24WVP.0S10L,2024-01-02 08:50:00.001,Good,2311.344482421875 +R0:Z24WVP.0S10L,2024-01-02 02:23:00.001,Good,2305.413330078125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 17:48:17.999,Good,6916.64501953125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 16:37:01.662,Good,6818.60595703125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:43:10.355,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:49:10.361,Good,19373.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 07:50:10.001,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:14:10.115,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 12:46:10.520,Good,19409.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 03:44:10.087,Good,19402.0 +R0:Z24WVP.0S10L,2024-01-02 15:37:00.001,Good,2266.861083984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:44:49.831,Good,6700.95947265625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:08:10.397,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:44:10.249,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:06:10.086,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:17:10.151,Good,19402.0 +R0:Z24WVP.0S10L,2024-01-02 22:48:00.001,Good,2294.14404296875 +R0:Z24WVP.0S10L,2024-01-02 10:34:01.001,Good,2346.337646484375 +R0:Z24WVP.0S10L,2024-01-02 08:11:00.001,Good,2311.344482421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 16:57:05.956,Good,6852.919921875 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:11:10.231,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:43:10.450,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:16:10.119,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:23:10.486,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:19:10.217,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:05:10.481,Good,19375.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 15:57:25.699,Good,6.73828125 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:59:58.650,Good,6.50244140625 +R0:Z24WVP.0S10L,2024-01-02 00:43:00.001,Good,2305.413330078125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:04:05.340,Good,7191.15380859375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:43:49.817,Good,6696.0576171875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 05:53:10.081,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:12:10.481,Good,19395.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 13:28:10.073,Good,19407.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:56:10.430,Good,19405.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 04:04:10.272,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 01:06:10.039,Good,19397.0 +R0:Z24WVP.0S10L,2024-01-02 12:34:00.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 03:28:40.945,Good,5715.66845703125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 14:39:10.051,Good,19411.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:45:10.038,Good,19400.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:56:10.387,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:54:10.321,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:15:10.412,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 15:59:10.328,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 10:26:10.316,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:12:10.230,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:10:10.095,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:58:10.047,Good,19377.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 15:20:17.109,Good,6.72802734375 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 09:13:45.909,Good,6.59765625 +R0:Z24WVP.0S10L,2024-01-02 13:29:00.001,Good,2264.488525390625 +R0:Z24WVP.0S10L,2024-01-02 12:27:00.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 17:49:18.753,Good,6921.546875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 11:09:10.224,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:01:10.092,Good,19401.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:34:10.447,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:15:10.160,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:00:10.322,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:33:10.275,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:19:10.287,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 01:39:10.074,Good,19398.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 11:41:24.009,Good,6.6650390625 +R0:Z24WVP.0S10L,2024-01-02 17:56:00.001,Good,2267.4541015625 +R0:Z24WVP.0S10L,2024-01-02 03:56:00.001,Good,2307.1923828125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:52:10.012,Good,19405.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:11:10.205,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:23:10.425,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 12:40:10.199,Good,19406.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:53:10.250,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:49:10.055,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 03:39:10.192,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:20:10.225,Good,19401.0 +R0:Z24WVP.0S10L,2024-01-02 00:58:00.001,Good,2304.81982421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:33:47.029,Good,6661.74365234375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 10:23:22.774,Good,6284.2939453125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:43:10.451,Good,19407.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:44:10.395,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 15:38:10.185,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:53:10.368,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:37:10.314,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:51:10.285,Good,19397.0 +R0:Z24WVP.0S10L,2024-01-02 23:49:00.001,Good,2216.44677734375 +R0:Z24WVP.0S10L,2024-01-02 19:29:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 04:20:00.000,Good,2307.78564453125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 16:25:10.277,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:43:10.246,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:55:10.339,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:16:10.039,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:22:10.398,Good,19410.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:01:10.150,Good,19409.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:45:10.004,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 08:14:10.047,Good,19405.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 20:51:37.349,Good,6.81982421875 +R0:Z24WVP.0S10L,2024-01-02 21:02:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 17:33:00.001,Good,2266.861083984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 14:51:34.876,Good,6544.09716796875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:03:22.788,Good,5911.74609375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:02:10.022,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:59:10.274,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:45:10.147,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:49:10.439,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:37:10.404,Good,19411.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:44:10.164,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:37:10.417,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 21:01:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 10:09:00.001,Good,2347.52392578125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 23:58:44.589,Good,7348.01611328125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:05:10.440,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:18:10.365,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:50:10.483,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:21:10.432,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 20:58:10.014,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:36:10.327,Good,19373.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 09:28:10.514,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 03:58:10.496,Good,19403.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 19:20:41.454,Good,7044.095703125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 10:00:17.477,Good,6269.58837890625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 16:55:10.391,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 16:24:10.199,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:26:10.395,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:50:10.417,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:23:10.080,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 13:24:10.225,Good,19408.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 09:07:10.167,Good,19403.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 23:12:34.643,Good,7313.70263671875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:33:10.295,Good,19397.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 20:41:10.113,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:33:10.245,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:46:10.279,Good,19402.0 +R0:Z24WVP.0S10L,2024-01-02 21:18:00.001,Good,2267.4541015625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 16:08:56.169,Good,6764.6845703125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:08:10.139,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 14:31:10.337,Good,19411.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 20:44:10.404,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:08:10.286,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:30:10.069,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 12:43:10.451,Good,19407.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:16:10.111,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:08:10.397,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 08:42:10.486,Good,19404.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 03:43:26.560,Good,6.42138671875 +R0:Z24WVP.0S10L,2024-01-02 16:50:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 05:20:00.001,Good,2307.78564453125 +R0:Z24WVP.0S10L,2024-01-02 01:10:01.001,Good,2304.81982421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 20:07:57.901,Good,7102.9189453125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:28:09.999,Good,19379.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:41:10.018,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:46:10.423,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:55:10.327,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:18:10.088,Good,19401.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:36:10.495,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:14:10.453,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:51:10.379,Good,19377.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 05:35:52.723,Good,6.48291015625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 13:07:08.204,Good,6416.646484375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:19:10.031,Good,19381.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:02:10.357,Good,19373.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 20:45:10.464,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 10:57:10.430,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:18:10.315,Good,19373.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:25:10.137,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 22:30:00.001,Good,2297.702880859375 +R0:Z24WVP.0S10L,2024-01-02 19:20:01.005,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 14:30:00.001,Good,2265.081787109375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:19:52.152,Good,6205.86279296875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:05:10.480,Good,19374.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:38:10.185,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:16:10.203,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:16:10.055,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:21:10.191,Good,19396.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 16:05:55.853,Good,6759.78271484375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:44:58.008,Good,6235.2744140625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:28:10.451,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:32:10.509,Good,19404.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:21:10.109,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:53:10.250,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:03:10.398,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:36:10.169,Good,19397.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 00:47:44.880,Good,6.3916015625 +R0:Z24WVP.0S10L,2024-01-02 21:58:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 11:41:00.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 12:06:51.126,Good,6348.01953125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:14:10.381,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 14:33:10.350,Good,19411.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:54:10.133,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:12:10.357,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:44:10.477,Good,19411.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 13:12:10.139,Good,19408.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 12:57:10.333,Good,19408.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 06:31:10.082,Good,19404.0 +R0:Z24WVP.0S10L,2024-01-02 15:12:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 15:09:00.001,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 11:36:42.912,Good,6318.607421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 03:21:39.440,Good,5710.7666015625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:07:10.148,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:36:10.137,Good,19401.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:40:10.234,Good,19400.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:01:10.327,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:56:10.144,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:52:10.136,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:42:10.236,Good,19375.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 09:54:57.274,Good,6.6181640625 +R0:Z24WVP.0S10L,2024-01-02 19:28:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 14:24:00.001,Good,2265.6748046875 +R0:Z24WVP.0S10L,2024-01-02 12:13:01.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 03:56:48.624,Good,5749.98193359375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:52:10.381,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 05:38:10.055,Good,19405.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:42:10.228,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:49:10.479,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:48:10.463,Good,19381.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 12:06:10.336,Good,19405.0 +R0:Z24WVP.0S10L,2024-01-02 17:14:00.010,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 08:22:00.001,Good,2310.751220703125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 18:41:32.154,Good,6975.46826171875 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:28:10.177,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:23:10.401,Good,19379.0 +R0:Z24WVP.0S10L,2024-01-02 08:28:00.001,Good,2310.751220703125 +R0:Z24WVP.0S10L,2024-01-02 06:09:00.001,Good,2309.56494140625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 22:20:23.671,Good,7264.68310546875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:57:10.259,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:00:10.076,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:43:10.057,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:28:10.414,Good,19381.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:32:10.320,Good,19410.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 18:16:58.170,Good,6.78564453125 +R0:Z24WVP.0S10L,2024-01-02 19:05:00.002,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 04:30:00.001,Good,2307.1923828125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 11:25:36.517,Good,6313.70556640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:56:00.471,Good,6245.07861328125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 19:42:10.236,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:06:10.054,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:06:10.039,Good,19397.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:45:10.154,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:36:10.390,Good,19378.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 20:18:28.932,Good,6.830078125 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 04:25:37.035,Good,6.43798828125 +R0:Z24WVP.0S10L,2024-01-02 21:44:01.001,Good,2266.861083984375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:32:10.391,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 17:36:10.430,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:27:10.202,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:38:10.325,Good,19396.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:53:10.356,Good,19382.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:21:10.429,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:58:10.178,Good,19403.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 20:49:36.771,Good,6.8212890625 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 16:20:31.311,Good,6.74560546875 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 02:38:10.555,Good,6.40771484375 +R0:Z24WVP.0S10L,2024-01-02 22:38:00.001,Good,2301.8544921875 +R0:Z24WVP.0S10L,2024-01-02 21:00:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 18:33:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 08:08:01.001,Good,2311.344482421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 16:17:57.885,Good,6789.1943359375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:58:54.526,Good,6730.37109375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 05:31:15.014,Good,5848.02099609375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 03:03:35.090,Good,5691.15869140625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 02:04:10.335,Good,19400.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:47:10.185,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:43:10.331,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:05:10.007,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 07:42:10.511,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 01:35:10.830,Good,19399.0 +R0:Z24WVP.0S10L,2024-01-02 14:31:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 13:51:00.001,Good,2264.488525390625 +R0:Z24WVP.0S10L,2024-01-02 03:03:00.001,Good,2306.006103515625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:40:10.354,Good,19401.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 08:07:10.462,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 04:33:10.486,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:12:10.158,Good,19409.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 08:09:10.185,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:50:10.172,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:28:10.247,Good,19378.0 +R0:Z24WVP.0S10L,2024-01-02 17:31:00.000,Good,2267.4541015625 +R0:Z24WVP.0S10L,2024-01-02 08:29:00.001,Good,2311.344482421875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:11:07.186,Good,7200.9580078125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 06:44:10.164,Good,19402.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:26:10.188,Good,19396.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:34:10.340,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:21:10.429,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:22:10.029,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:46:10.365,Good,19397.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:06:10.388,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:27:10.117,Good,19379.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:57:10.479,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:43:10.430,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:04:10.204,Good,19409.0 +R0:Z24WVP.0S10L,2024-01-02 22:43:00.001,Good,2299.48193359375 +R0:Z24WVP.0S10L,2024-01-02 21:11:00.001,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 13:46:17.703,Good,6450.9599609375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:28:10.414,Good,19380.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:14:10.016,Good,19384.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 13:30:10.275,Good,19409.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:59:10.057,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:36:10.072,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:18:10.195,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:12:10.208,Good,19375.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 11:15:10.041,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 07:06:10.473,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:41:10.441,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 18:17:10.032,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:53:10.203,Good,19376.0 +R0:Z24WVP.0S10L,2024-01-02 21:32:00.001,Good,2266.26806640625 +R0:Z24WVP.0S10L,2024-01-02 18:32:00.001,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 22:22:23.814,Good,7259.78125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 05:49:19.748,Good,5867.62841796875 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:54:10.133,Good,19379.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:48:10.312,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 09:14:10.055,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:57:10.117,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 22:02:10.069,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 12:42:10.399,Good,19408.0 +R0:Z24WVP.0S10L,2024-01-02 20:10:00.001,Good,2266.861083984375 +R0:Z24WVP.0S10L,2024-01-02 14:51:00.001,Good,2266.26806640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 10:45:28.351,Good,6299.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 05:03:06.771,Good,5833.31494140625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:08:10.425,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:15:10.412,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 16:11:10.167,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:49:10.462,Good,19373.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 10:14:10.274,Good,19401.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:04:10.483,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 07:35:10.184,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:32:10.219,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:40:10.207,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:06:10.401,Good,19410.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 11:14:17.402,Good,6.65478515625 +R0:Z24WVP.0S10L,2024-01-02 09:37:00.001,Good,2311.937255859375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:56:10.312,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:47:10.271,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:53:10.157,Good,19378.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:56:10.250,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:19:10.376,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 19:02:10.026,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:01:10.129,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:23:10.045,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:16:10.242,Good,19394.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 08:39:10.378,Good,19402.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 21:14:08.404,Good,7200.9580078125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 08:34:56.025,Good,6220.56884765625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:33:30.708,Good,5985.275390625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:43:10.001,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:44:10.247,Good,19380.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 19:16:10.265,Good,19374.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 18:47:10.185,Good,19374.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 00:40:10.497,Good,19397.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 20:21:10.333,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:39:10.184,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:21:10.276,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 15:10:10.346,Good,19388.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 14:30:10.243,Good,19410.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 10:24:10.145,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 16:22:00.001,Good,2266.861083984375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 22:37:27.473,Good,7274.48681640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 12:43:00.288,Good,6406.8427734375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:42:10.247,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 11:47:10.138,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:26:10.073,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:00:10.422,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:44:10.477,Good,19411.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:02:10.169,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 20:35:10.368,Good,19374.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:46:10.011,Good,19375.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 19:36:10.327,Good,19373.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 18:33:10.253,Good,19373.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:06:10.054,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:00:10.012,Good,19402.0 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 18:41:04.113,Good,6.7958984375 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 10:44:09.973,Good,6.642578125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 04:59:05.845,Good,5828.4130859375 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:59:10.033,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:58:10.317,Good,19379.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:02:10.333,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 03:30:10.500,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 02:44:10.167,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:56:10.285,Good,19405.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 02:04:10.335,Good,19400.0 +R0:Z24WVP.0S10L,2024-01-02 12:09:00.001,Good,2264.488525390625 +1N325T3MTOR-P0L29:9.T0,2024-01-02 23:38:10.214,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 07:41:10.491,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:45:10.083,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:08:10.152,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 01:09:10.227,Good,19397.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:35:10.227,Good,19403.0 +R0:Z24WVP.0S10L,2024-01-02 23:43:00.001,Good,2295.330322265625 +R0:Z24WVP.0S10L,2024-01-02 23:35:00.001,Good,2297.702880859375 +R0:Z24WVP.0S10L,2024-01-02 12:12:00.001,Good,2265.081787109375 +R0:Z24WVP.0S10L,2024-01-02 05:33:00.001,Good,2308.378662109375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 15:07:39.464,Good,6583.3125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:39:10.372,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 09:23:10.497,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 16:29:10.143,Good,19378.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:15:10.019,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 00:43:10.184,Good,19396.0 +R0:Z24WVP.0S10L,2024-01-02 13:14:00.001,Good,2265.081787109375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 06:51:34.506,Good,6044.0986328125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 23:25:10.443,Good,19377.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 21:43:10.195,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 15:12:10.505,Good,19386.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 12:42:10.399,Good,19408.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 03:38:10.129,Good,19403.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 01:52:10.488,Good,19401.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 06:03:10.114,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 05:29:10.186,Good,19403.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 01:25:10.483,Good,19398.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 01:12:10.421,Good,19398.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:41:10.301,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 05:57:10.423,Good,19402.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 04:12:10.078,Good,19403.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 07:29:41.930,Good,6147.03955078125 +1N325T3MTOR-P0L29:9.T0,2024-01-02 22:12:10.357,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:28:10.469,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 10:34:10.422,Good,19403.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 17:01:10.327,Good,19376.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 11:54:10.205,Good,19404.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 08:47:10.339,Good,19404.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 16:06:55.961,Good,6754.880859375 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 14:24:27.995,Good,6490.17578125 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 07:33:43.150,Good,6156.84326171875 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 02:47:30.694,Good,5671.55078125 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 22:55:10.198,Good,19378.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:30:10.442,Good,19376.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:04:10.452,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 15:37:10.090,Good,19376.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 13:12:10.139,Good,19408.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 04:20:10.029,Good,19404.0 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 11:57:48.785,Good,6333.3134765625 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 20:46:10.070,Good,19375.0 +_LT2EPL-9PM0.OROTENV3:,2024-01-02 11:18:10.090,Good,19404.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 18:17:10.032,Good,19374.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 16:38:10.380,Good,19377.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 14:34:10.348,Good,19412.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 00:22:10.264,Good,19395.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 23:14:10.381,Good,19377.0 +TT33-01M9Z2L9:P20.AIRO5N,2024-01-02 21:10:10.203,Good,19376.0 +value_range, 2024-01-02 03:49:45.000, Good, 1 +value_range, 2024-01-02 07:53:11.000, Good, 2 +value_range, 2024-01-02 11:56:42.000, Good, 3 +value_range, 2024-01-02 16:00:12.000, Good, 4 +value_range, 2024-01-02 20:03:46.000, Good, 5 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 17:29:47.361,Good,6.7666015625 +O:05RI0.2T2M6STN6_PP-I165AT,2024-01-02 11:08:16.131,Good,6.6533203125 +R0:Z24WVP.0S10L,2024-01-02 10:54:00.001,Good,2264.488525390625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 11:15:36.517,Good,6313.70556640625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 03:52:47.354,Good,5740.17822265625 +-4O7LSSAM_3EA02:2GT7E02I_R_MP,2024-01-02 01:56:15.905,Good,5627.43310546875 +FLATLINE_TEST,2024-01-02 22:50:10.417,Good,19379.0 +FLATLINE_TEST,2024-01-02 14:57:10.372,Good,0 +FLATLINE_TEST,2024-01-02 02:49:10.408,Good,0 +FLATLINE_TEST,2024-01-02 02:35:10.511,Good,0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 21:51:10.219,Good,19402.0 +1N325T3MTOR-P0L29:9.T0,2024-01-02 17:08:10.242,Good,19402.0 +MISSING_DATA,2024-01-02 00:08:10.000,Good,19379.0 +MISSING_DATA,2024-01-02 00:08:11.000,Good,1 +MISSING_DATA,2024-01-02 00:08:13.000,Good,1 +MISSING_DATA,2024-01-02 00:08:14.000,Good,1 +MISSING_DATA_PATTERN,2024-01-05 00:02:10.000,Good,19379.0 +MISSING_DATA_PATTERN,2024-01-05 00:02:11.000,Good,1 +MISSING_DATA_PATTERN,2024-01-05 00:02:13.000,Good,1 +MISSING_DATA_PATTERN,2024-01-05 00:02:14.000,Good,1 + diff --git a/tests/sdk/python/rtdip_sdk/pipelines/logging/test_log_collection.py b/tests/sdk/python/rtdip_sdk/pipelines/logging/test_log_collection.py index 27bbff1fb..e01a3e125 100644 --- a/tests/sdk/python/rtdip_sdk/pipelines/logging/test_log_collection.py +++ b/tests/sdk/python/rtdip_sdk/pipelines/logging/test_log_collection.py @@ -41,7 +41,19 @@ def spark(): def test_logger_manager_basic_function(spark): - df = DataFrame() + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:00.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:01:25.000", "Good", "0.150000006"), + ( + "A2PS64V0J.:ZUX09R", + "2024-01-02 00:01:41.000", + "Good", + "0.340000004", + ), # Missing interval (25s to 41s) + ], + ["TagName", "EventTime", "Status", "Value"], + ) monitor = IdentifyMissingDataInterval( df=df, interval="10s", @@ -54,20 +66,13 @@ def test_logger_manager_basic_function(spark): def test_df_output(spark, caplog): log_collector = RuntimeLogCollector(spark) - data = [ - (1, "2024-02-11 00:00:00.000"), - (2, "2024-02-11 00:00:10.000"), - (3, "2024-02-11 00:00:20.000"), - (4, "2024-02-11 00:00:36.000"), # Missing interval (20s to 36s) - (5, "2024-02-11 00:00:45.000"), - (6, "2024-02-11 00:00:55.000"), - (7, "2024-02-11 00:01:05.000"), - (8, "2024-02-11 00:01:15.000"), - (9, "2024-02-11 00:01:25.000"), - (10, "2024-02-11 00:01:41.000"), # Missing interval (25s to 41s) - ] - columns = ["Index", "EventTime"] - df = spark.createDataFrame(data, schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:00.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:10.000", "Good", "0.119999997"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) monitor = IdentifyMissingDataInterval( df=df, @@ -83,25 +88,18 @@ def test_df_output(spark, caplog): result_df = log_handler.get_logs_as_df() - assert result_df.count() == 6 + assert result_df.count() == 4 def test_unique_dataframes(spark, caplog): log_collector = RuntimeLogCollector(spark) - data = [ - (1, "2024-02-11 00:00:00.000"), - (2, "2024-02-11 00:00:10.000"), - (3, "2024-02-11 00:00:20.000"), - (4, "2024-02-11 00:00:36.000"), # Missing interval (20s to 36s) - (5, "2024-02-11 00:00:45.000"), - (6, "2024-02-11 00:00:55.000"), - (7, "2024-02-11 00:01:05.000"), - (8, "2024-02-11 00:01:15.000"), - (9, "2024-02-11 00:01:25.000"), - (10, "2024-02-11 00:01:41.000"), # Missing interval (25s to 41s) - ] - columns = ["Index", "EventTime"] - df = spark.createDataFrame(data, schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:00.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:10.000", "Good", "0.119999997"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) logger = LoggerManager().create_logger("Test_Logger") monitor = IdentifyMissingDataInterval( df=df, @@ -126,20 +124,13 @@ def test_unique_dataframes(spark, caplog): def test_file_logging(spark, caplog): log_collector = RuntimeLogCollector(spark) - data = [ - (1, "2024-02-11 00:00:00.000"), - (2, "2024-02-11 00:00:10.000"), - (3, "2024-02-11 00:00:20.000"), - (4, "2024-02-11 00:00:36.000"), # Missing interval (20s to 36s) - (5, "2024-02-11 00:00:45.000"), - (6, "2024-02-11 00:00:55.000"), - (7, "2024-02-11 00:01:05.000"), - (8, "2024-02-11 00:01:15.000"), - (9, "2024-02-11 00:01:25.000"), - (10, "2024-02-11 00:01:41.000"), # Missing interval (25s to 41s) - ] - columns = ["Index", "EventTime"] - df = spark.createDataFrame(data, schema=columns) + df = spark.createDataFrame( + [ + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:00.000", "Good", "0.129999995"), + ("A2PS64V0J.:ZUX09R", "2024-01-02 00:00:10.000", "Good", "0.119999997"), + ], + ["TagName", "EventTime", "Status", "Value"], + ) monitor = IdentifyMissingDataInterval( df=df, interval="10s", @@ -153,6 +144,6 @@ def test_file_logging(spark, caplog): with open("./logs.log", "r") as f: logs = f.readlines() - assert len(logs) == 6 + assert len(logs) == 4 if os.path.exists("./logs.log"): os.remove("./logs.log")