text:
use crate::rocks_metrics_defs::*;
use engine_traits::CF_DEFAULT;
use lazy_static::lazy_static;
use prometheus::*;
use prometheus_static_metric::*;

use rocksdb::{
    DBStatisticsHistogramType as HistType, DBStatisticsTickerType as TickerType, HistogramData, DB,
};
use std::i64;
use tikv_util::warn;

make_auto_flush_static_metric! {
    pub label_enum TickerName {
        kv,
        raft,
    }

    pub label_enum TickerEnum {
        block_cache_add,
        block_cache_add_failures,
        block_cache_byte_read,
        block_cache_byte_write,
        block_cache_data_add,
        block_cache_data_bytes_insert,
        block_cache_data_hit,
        block_cache_data_miss,
        block_cache_filter_add,
        block_cache_filter_bytes_evict,
        block_cache_filter_bytes_insert,
        block_cache_filter_hit,
        block_cache_filter_miss,
        block_cache_hit,
        block_cache_index_add,
        block_cache_index_bytes_evict,
        block_cache_index_bytes_insert,
        block_cache_index_hit,
        block_cache_index_miss,
        block_cache_miss,
        bloom_prefix_checked,
        bloom_prefix_useful,
        bloom_useful,
        bytes_overwritten,
        bytes_read,
        bytes_relocated,
        bytes_written,
        compaction_key_drop_newer_entry,
        compaction_key_drop_obsolete,
        compaction_key_drop_range_del,
        flush_write_bytes,
        gc_input_files_count,
        gc_output_files_count,
        get_hit_l0,
        get_hit_l1,
        get_hit_l2_and_up,
        iter_bytes_read,
        keys_overwritten,
        keys_read,
        keys_relocated,
        keys_updated,
        keys_written,
        memtable_hit,
        memtable_miss,
        no_file_closes,
        no_file_errors,
        no_file_opens,
        number_blob_get,
        number_blob_next,
        number_blob_prev,
        number_blob_seek,
        number_db_next,
        number_db_next_found,
        number_db_prev,
        number_db_prev_found,
        number_db_seek,
        number_db_seek_found,
        optimized_del_drop_obsolete,
        range_del_drop_obsolete,
        read_amp_estimate_useful_bytes,
        read_amp_total_read_bytes,
        wal_file_bytes,
        write_done_by_other,
        write_done_by_self,
        write_timeout,
        write_with_wal,
        blob_cache_hit,
        blob_cache_miss,
        no_need,
        remain,
        discardable,
        sample,
        small_file,
        failure,
        success,
        trigger_next,
    }

    pub struct EngineTickerMetrics : LocalIntCounter {
        "db" => TickerName,
        "type" => TickerEnum,
    }

    pub struct SimpleEngineTickerMetrics : LocalIntCounter {
        "db" => TickerName,
    }
}

pub fn flush_engine_ticker_metrics(t: TickerType, value: u64, name: &str) {
    let v = value as i64;
    if v < 0 {
        warn!("engine ticker is overflow";
            "ticker" => ?t, "value" => value
        );
        return;
    }

    let name_enum = match name {
        "kv" => TickerName::kv,
        "raft" => TickerName::raft,
        unexpected => panic!("unexpected name {}", unexpected),
    };

    match t {
        TickerType::BlockCacheMiss => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_miss
                .inc_by(v);
        }
        TickerType::BlockCacheHit => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_hit
                .inc_by(v);
        }
        TickerType::BlockCacheAdd => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_add
                .inc_by(v);
        }
        TickerType::BlockCacheAddFailures => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_add_failures
                .inc_by(v);
        }
        TickerType::BlockCacheIndexMiss => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_index_miss
                .inc_by(v);
        }
        TickerType::BlockCacheIndexHit => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_index_hit
                .inc_by(v);
        }
        TickerType::BlockCacheIndexAdd => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_index_add
                .inc_by(v);
        }
        TickerType::BlockCacheIndexBytesInsert => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_index_bytes_insert
                .inc_by(v);
        }
        TickerType::BlockCacheIndexBytesEvict => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_index_bytes_evict
                .inc_by(v);
        }
        TickerType::BlockCacheFilterMiss => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_filter_miss
                .inc_by(v);
        }
        TickerType::BlockCacheFilterHit => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_filter_hit
                .inc_by(v);
        }
        TickerType::BlockCacheFilterAdd => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_filter_add
                .inc_by(v);
        }
        TickerType::BlockCacheFilterBytesInsert => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_filter_bytes_insert
                .inc_by(v);
        }
        TickerType::BlockCacheFilterBytesEvict => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_filter_bytes_evict
                .inc_by(v);
        }
        TickerType::BlockCacheDataMiss => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_data_miss
                .inc_by(v);
        }
        TickerType::BlockCacheDataHit => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_data_hit
                .inc_by(v);
        }
        TickerType::BlockCacheDataAdd => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_data_add
                .inc_by(v);
        }
        TickerType::BlockCacheDataBytesInsert => {
            STORE_ENGINE_CACHE_EFFICIENCY
                .get(name_enum)
                .block_cache_data_bytes_insert
                .inc_by(v);
        }
        TickerType::BlockCacheBytesRead => {
            STORE_ENGINE_FLOW
                .get(name_enum)
                .block_cache_byte_read
                .inc_by(v);
        }
        TickerType::BlockCacheBytesWrite => {
            STORE_ENGINE_FLOW
                .get(name_enum)
                .block_cache_byte_write
                .inc_by(v);
        }
        TickerType::BloomFilterUseful => {
            STORE_ENGINE_BLOOM_EFFICIENCY
                .get(name_enum)
                .bloom_useful
                .inc_by(v);
        }
        TickerType::MemtableHit => {
            STORE_ENGINE_MEMTABLE_EFFICIENCY
                .get(name_enum)
                .memtable_hit
                .inc_by(v);
        }
        TickerType::MemtableMiss => {
            STORE_ENGINE_MEMTABLE_EFFICIENCY
                .get(name_enum)
                .memtable_miss
                .inc_by(v);
        }
        TickerType::GetHitL0 => {
            STORE_ENGINE_GET_SERVED.get(name_enum).get_hit_l0.inc_by(v);
        }
        TickerType::GetHitL1 => {
            STORE_ENGINE_GET_SERVED.get(name_enum).get_hit_l1.inc_by(v);
        }
        TickerType::GetHitL2AndUp => {
            STORE_ENGINE_GET_SERVED
                .get(name_enum)
                .get_hit_l2_and_up
                .inc_by(v);
        }
        TickerType::CompactionKeyDropNewerEntry => {
            STORE_ENGINE_COMPACTION_DROP
                .get(name_enum)
                .compaction_key_drop_newer_entry
                .inc_by(v);
        }
        TickerType::CompactionKeyDropObsolete => {
            STORE_ENGINE_COMPACTION_DROP
                .get(name_enum)
                .compaction_key_drop_obsolete
                .inc_by(v);
        }
        TickerType::CompactionKeyDropRangeDel => {
            STORE_ENGINE_COMPACTION_DROP
                .get(name_enum)
                .compaction_key_drop_range_del
                .inc_by(v);
        }
        TickerType::CompactionRangeDelDropObsolete => {
            STORE_ENGINE_COMPACTION_DROP
                .get(name_enum)
                .range_del_drop_obsolete
                .inc_by(v);
        }
        TickerType::CompactionOptimizedDelDropObsolete => {
            STORE_ENGINE_COMPACTION_DROP
                .get(name_enum)
                .optimized_del_drop_obsolete
                .inc_by(v);
        }
        TickerType::NumberKeysWritten => {
            STORE_ENGINE_FLOW.get(name_enum).keys_written.inc_by(v);
        }
        TickerType::NumberKeysRead => {
            STORE_ENGINE_FLOW.get(name_enum).keys_read.inc_by(v);
        }
        TickerType::NumberKeysUpdated => {
            STORE_ENGINE_FLOW.get(name_enum).keys_updated.inc_by(v);
        }
        TickerType::BytesWritten => {
            STORE_ENGINE_FLOW.get(name_enum).bytes_written.inc_by(v);
        }
        TickerType::BytesRead => {
            STORE_ENGINE_FLOW.get(name_enum).bytes_read.inc_by(v);
        }
        TickerType::NumberDbSeek => {
            STORE_ENGINE_LOCATE.get(name_enum).number_db_seek.inc_by(v);
        }
        TickerType::NumberDbNext => {
            STORE_ENGINE_LOCATE.get(name_enum).number_db_next.inc_by(v);
        }
        TickerType::NumberDbPrev => {
            STORE_ENGINE_LOCATE.get(name_enum).number_db_prev.inc_by(v);
        }
        TickerType::NumberDbSeekFound => {
            STORE_ENGINE_LOCATE
                .get(name_enum)
                .number_db_seek_found
                .inc_by(v);
        }
        TickerType::NumberDbNextFound => {
            STORE_ENGINE_LOCATE
                .get(name_enum)
                .number_db_next_found
                .inc_by(v);
        }
        TickerType::NumberDbPrevFound => {
            STORE_ENGINE_LOCATE
                .get(name_enum)
                .number_db_prev_found
                .inc_by(v);
        }
        TickerType::IterBytesRead => {
            STORE_ENGINE_FLOW.get(name_enum).iter_bytes_read.inc_by(v);
        }
        TickerType::NoFileCloses => {
            STORE_ENGINE_FILE_STATUS
                .get(name_enum)
                .no_file_closes
                .inc_by(v);
        }
        TickerType::NoFileOpens => {
            STORE_ENGINE_FILE_STATUS
                .get(name_enum)
                .no_file_opens
                .inc_by(v);
        }
        TickerType::NoFileErrors => {
            STORE_ENGINE_FILE_STATUS
                .get(name_enum)
                .no_file_errors
                .inc_by(v);
        }
        TickerType::StallMicros => {
            STORE_ENGINE_STALL_MICROS.get(name_enum).inc_by(v);
        }
        TickerType::BloomFilterPrefixChecked => {
            STORE_ENGINE_BLOOM_EFFICIENCY
                .get(name_enum)
                .bloom_prefix_checked
                .inc_by(v);
        }
        TickerType::BloomFilterPrefixUseful => {
            STORE_ENGINE_BLOOM_EFFICIENCY
                .get(name_enum)
                .bloom_prefix_useful
                .inc_by(v);
        }
        TickerType::WalFileSynced => {
            STORE_ENGINE_WAL_FILE_SYNCED.get(name_enum).inc_by(v);
        }
        TickerType::WalFileBytes => {
            STORE_ENGINE_FLOW.get(name_enum).wal_file_bytes.inc_by(v);
        }
        TickerType::WriteDoneBySelf => {
            STORE_ENGINE_WRITE_SERVED
                .get(name_enum)
                .write_done_by_self
                .inc_by(v);
        }
        TickerType::WriteDoneByOther => {
            STORE_ENGINE_WRITE_SERVED
                .get(name_enum)
                .write_done_by_other
                .inc_by(v);
        }
        TickerType::WriteTimedout => {
            STORE_ENGINE_WRITE_SERVED
                .get(name_enum)
                .write_timeout
                .inc_by(v);
        }
        TickerType::WriteWithWal => {
            STORE_ENGINE_WRITE_SERVED
                .get(name_enum)
                .write_with_wal
                .inc_by(v);
        }
        TickerType::CompactReadBytes => {
            STORE_ENGINE_COMPACTION_FLOW
                .get(name_enum)
                .bytes_read
                .inc_by(v);
        }
        TickerType::CompactWriteBytes => {
            STORE_ENGINE_COMPACTION_FLOW
                .get(name_enum)
                .bytes_written
                .inc_by(v);
        }
        TickerType::FlushWriteBytes => {
            STORE_ENGINE_FLOW.get(name_enum).flush_write_bytes.inc_by(v);
        }
        TickerType::ReadAmpEstimateUsefulBytes => {
            STORE_ENGINE_READ_AMP_FLOW
                .get(name_enum)
                .read_amp_estimate_useful_bytes
                .inc_by(v);
        }
        TickerType::ReadAmpTotalReadBytes => {
            STORE_ENGINE_READ_AMP_FLOW
                .get(name_enum)
                .read_amp_total_read_bytes
                .inc_by(v);
        }
        TickerType::TitanNumGet => {
            STORE_ENGINE_BLOB_LOCATE
                .get(name_enum)
                .number_blob_get
                .inc_by(v);
        }
        TickerType::TitanNumSeek => {
            STORE_ENGINE_BLOB_LOCATE
                .get(name_enum)
                .number_blob_seek
                .inc_by(v);
        }
        TickerType::TitanNumNext => {
            STORE_ENGINE_BLOB_LOCATE
                .get(name_enum)
                .number_blob_next
                .inc_by(v);
        }
        TickerType::TitanNumPrev => {
            STORE_ENGINE_BLOB_LOCATE
                .get(name_enum)
                .number_blob_prev
                .inc_by(v);
        }
        TickerType::TitanBlobFileNumKeysWritten => {
            STORE_ENGINE_BLOB_FLOW.get(name_enum).keys_written.inc_by(v);
        }
        TickerType::TitanBlobFileNumKeysRead => {
            STORE_ENGINE_BLOB_FLOW.get(name_enum).keys_read.inc_by(v);
        }
        TickerType::TitanBlobFileBytesWritten => {
            STORE_ENGINE_BLOB_FLOW
                .get(name_enum)
                .bytes_written
                .inc_by(v);
        }
        TickerType::TitanBlobFileBytesRead => {
            STORE_ENGINE_BLOB_FLOW.get(name_enum).bytes_read.inc_by(v);
        }
        TickerType::TitanBlobFileSynced => STORE_ENGINE_BLOB_FILE_SYNCED.get(name_enum).inc_by(v),
        TickerType::TitanGcNumFiles => {
            STORE_ENGINE_BLOB_GC_FILE
                .get(name_enum)
                .gc_input_files_count
                .inc_by(v);
        }
        TickerType::TitanGcNumNewFiles => {
            STORE_ENGINE_BLOB_GC_FILE
                .get(name_enum)
                .gc_output_files_count
                .inc_by(v);
        }
        TickerType::TitanGcNumKeysOverwritten => {
            STORE_ENGINE_BLOB_GC_FLOW
                .get(name_enum)
                .keys_overwritten
                .inc_by(v);
        }
        TickerType::TitanGcNumKeysRelocated => {
            STORE_ENGINE_BLOB_GC_FLOW
                .get(name_enum)
                .keys_relocated
                .inc_by(v);
        }
        TickerType::TitanGcBytesOverwritten => {
            STORE_ENGINE_BLOB_GC_FLOW
                .get(name_enum)
                .bytes_overwritten
                .inc_by(v);
        }
        TickerType::TitanGcBytesRelocated => {
            STORE_ENGINE_BLOB_GC_FLOW
                .get(name_enum)
                .bytes_relocated
                .inc_by(v);
        }
        TickerType::TitanGcBytesWritten => {
            STORE_ENGINE_BLOB_GC_FLOW
                .get(name_enum)
                .bytes_written
                .inc_by(v);
        }
        TickerType::TitanGcBytesRead => {
            STORE_ENGINE_BLOB_GC_FLOW
                .get(name_enum)
                .bytes_read
                .inc_by(v);
        }
        TickerType::TitanBlobCacheHit => {
            STORE_ENGINE_BLOB_CACHE_EFFICIENCY
                .get(name_enum)
                .blob_cache_hit
                .inc_by(v);
        }
        TickerType::TitanBlobCacheMiss => {
            STORE_ENGINE_BLOB_CACHE_EFFICIENCY
                .get(name_enum)
                .blob_cache_miss
                .inc_by(v);
        }
        TickerType::TitanGcNoNeed => {
            STORE_ENGINE_BLOB_GC_ACTION.get(name_enum).no_need.inc_by(v);
        }
        TickerType::TitanGcRemain => {
            STORE_ENGINE_BLOB_GC_ACTION.get(name_enum).remain.inc_by(v);
        }
        TickerType::TitanGcDiscardable => {
            STORE_ENGINE_BLOB_GC_ACTION
                .get(name_enum)
                .discardable
                .inc_by(v);
        }
        TickerType::TitanGcSample => {
            STORE_ENGINE_BLOB_GC_ACTION.get(name_enum).sample.inc_by(v);
        }
        TickerType::TitanGcSmallFile => {
            STORE_ENGINE_BLOB_GC_ACTION
                .get(name_enum)
                .small_file
                .inc_by(v);
        }
        TickerType::TitanGcFailure => {
            STORE_ENGINE_BLOB_GC_ACTION.get(name_enum).failure.inc_by(v);
        }
        TickerType::TitanGcSuccess => {
            STORE_ENGINE_BLOB_GC_ACTION.get(name_enum).success.inc_by(v);
        }
        TickerType::TitanGcTriggerNext => {
            STORE_ENGINE_BLOB_GC_ACTION
                .get(name_enum)
                .trigger_next
                .inc_by(v);
        }
        _ => {}
    }
}

macro_rules! engine_histogram_metrics {
    ($metric:ident, $prefix:expr, $db:expr, $value:expr) => {
        $metric
            .with_label_values(&[$db, concat!($prefix, "_median")])
            .set($value.median);
        $metric
            .with_label_values(&[$db, concat!($prefix, "_percentile95")])
            .set($value.percentile95);
        $metric
            .with_label_values(&[$db, concat!($prefix, "_percentile99")])
            .set($value.percentile99);
        $metric
            .with_label_values(&[$db, concat!($prefix, "_average")])
            .set($value.average);
        $metric
            .with_label_values(&[$db, concat!($prefix, "_standard_deviation")])
            .set($value.standard_deviation);
        $metric
            .with_label_values(&[$db, concat!($prefix, "_max")])
            .set($value.max);
    };
}

pub fn flush_engine_histogram_metrics(t: HistType, value: HistogramData, name: &str) {
    match t {
        HistType::DbGet => {
            engine_histogram_metrics!(STORE_ENGINE_GET_VEC, "get", name, value);
        }
        HistType::DbWrite => {
            engine_histogram_metrics!(STORE_ENGINE_WRITE_VEC, "write", name, value);
        }
        HistType::CompactionTime => {
            engine_histogram_metrics!(
                STORE_ENGINE_COMPACTION_TIME_VEC,
                "compaction_time",
                name,
                value
            );
        }
        HistType::TableSyncMicros => {
            engine_histogram_metrics!(STORE_ENGINE_TABLE_SYNC_VEC, "table_sync", name, value);
        }
        HistType::CompactionOutfileSyncMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_COMPACTION_OUTFILE_SYNC_VEC,
                "compaction_outfile_sync",
                name,
                value
            );
        }
        HistType::WalFileSyncMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_WAL_FILE_SYNC_MICROS_VEC,
                "wal_file_sync",
                name,
                value
            );
        }
        HistType::ManifestFileSyncMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_MANIFEST_FILE_SYNC_VEC,
                "manifest_file_sync",
                name,
                value
            );
        }
        HistType::StallL0SlowdownCount => {
            engine_histogram_metrics!(
                STORE_ENGINE_STALL_L0_SLOWDOWN_COUNT_VEC,
                "stall_l0_slowdown_count",
                name,
                value
            );
        }
        HistType::StallMemtableCompactionCount => {
            engine_histogram_metrics!(
                STORE_ENGINE_STALL_MEMTABLE_COMPACTION_COUNT_VEC,
                "stall_memtable_compaction_count",
                name,
                value
            );
        }
        HistType::StallL0NumFilesCount => {
            engine_histogram_metrics!(
                STORE_ENGINE_STALL_L0_NUM_FILES_COUNT_VEC,
                "stall_l0_num_files_count",
                name,
                value
            );
        }
        HistType::HardRateLimitDelayCount => {
            engine_histogram_metrics!(
                STORE_ENGINE_HARD_RATE_LIMIT_DELAY_VEC,
                "hard_rate_limit_delay",
                name,
                value
            );
        }
        HistType::SoftRateLimitDelayCount => {
            engine_histogram_metrics!(
                STORE_ENGINE_SOFT_RATE_LIMIT_DELAY_VEC,
                "soft_rate_limit_delay",
                name,
                value
            );
        }
        HistType::NumFilesInSingleCompaction => {
            engine_histogram_metrics!(
                STORE_ENGINE_NUM_FILES_IN_SINGLE_COMPACTION_VEC,
                "num_files_in_single_compaction",
                name,
                value
            );
        }
        HistType::DbSeek => {
            engine_histogram_metrics!(STORE_ENGINE_SEEK_MICROS_VEC, "seek", name, value);
        }
        HistType::WriteStall => {
            engine_histogram_metrics!(STORE_ENGINE_WRITE_STALL_VEC, "write_stall", name, value);
        }
        HistType::SstReadMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_SST_READ_MICROS_VEC,
                "sst_read_micros",
                name,
                value
            );
        }
        HistType::NumSubcompactionsScheduled => {
            engine_histogram_metrics!(
                STORE_ENGINE_NUM_SUBCOMPACTION_SCHEDULED_VEC,
                "num_subcompaction_scheduled",
                name,
                value
            );
        }
        HistType::BytesPerRead => {
            engine_histogram_metrics!(
                STORE_ENGINE_BYTES_PER_READ_VEC,
                "bytes_per_read",
                name,
                value
            );
        }
        HistType::BytesPerWrite => {
            engine_histogram_metrics!(
                STORE_ENGINE_BYTES_PER_WRITE_VEC,
                "bytes_per_write",
                name,
                value
            );
        }
        HistType::BytesCompressed => {
            engine_histogram_metrics!(
                STORE_ENGINE_BYTES_COMPRESSED_VEC,
                "bytes_compressed",
                name,
                value
            );
        }
        HistType::BytesDecompressed => {
            engine_histogram_metrics!(
                STORE_ENGINE_BYTES_DECOMPRESSED_VEC,
                "bytes_decompressed",
                name,
                value
            );
        }
        HistType::CompressionTimesNanos => {
            engine_histogram_metrics!(
                STORE_ENGINE_COMPRESSION_TIMES_NANOS_VEC,
                "compression_time_nanos",
                name,
                value
            );
        }
        HistType::DecompressionTimesNanos => {
            engine_histogram_metrics!(
                STORE_ENGINE_DECOMPRESSION_TIMES_NANOS_VEC,
                "decompression_time_nanos",
                name,
                value
            );
        }
        HistType::DbWriteWalTime => {
            engine_histogram_metrics!(
                STORE_ENGINE_WRITE_WAL_TIME_VEC,
                "write_wal_micros",
                name,
                value
            );
        }
        HistType::TitanKeySize => {
            engine_histogram_metrics!(STORE_ENGINE_BLOB_KEY_SIZE_VEC, "blob_key_size", name, value);
        }
        HistType::TitanValueSize => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_VALUE_SIZE_VEC,
                "blob_value_size",
                name,
                value
            );
        }
        HistType::TitanGetMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_GET_MICROS_VEC,
                "blob_get_micros",
                name,
                value
            );
        }
        HistType::TitanSeekMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_SEEK_MICROS_VEC,
                "blob_seek_micros",
                name,
                value
            );
        }
        HistType::TitanNextMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_NEXT_MICROS_VEC,
                "blob_next_micros",
                name,
                value
            );
        }
        HistType::TitanPrevMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_PREV_MICROS_VEC,
                "blob_prev_micros",
                name,
                value
            );
        }
        HistType::TitanBlobFileWriteMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_FILE_WRITE_MICROS_VEC,
                "blob_file_write_micros",
                name,
                value
            );
        }
        HistType::TitanBlobFileReadMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_FILE_READ_MICROS_VEC,
                "blob_file_read_micros",
                name,
                value
            );
        }
        HistType::TitanBlobFileSyncMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_FILE_SYNC_MICROS_VEC,
                "blob_file_sync_micros",
                name,
                value
            );
        }
        HistType::TitanGcMicros => {
            engine_histogram_metrics!(
                STORE_ENGINE_BLOB_GC_MICROS_VEC,
                "blob_gc_micros",
                name,
                value
            );
        }
        HistType::TitanGcInputFileSize => {
            engine_histogram_metrics!(
                STORE_ENGINE_GC_INPUT_BLOB_FILE_SIZE_VEC,
                "blob_gc_input_file",
                name,
                value
            );
        }
        HistType::TitanGcOutputFileSize => {
            engine_histogram_metrics!(
                STORE_ENGINE_GC_OUTPUT_BLOB_FILE_SIZE_VEC,
                "blob_gc_output_file",
                name,
                value
            );
        }
        HistType::TitanIterTouchBlobFileCount => {
            engine_histogram_metrics!(
                STORE_ENGINE_ITER_TOUCH_BLOB_FILE_COUNT_VEC,
                "blob_iter_touch_blob_file_count",
                name,
                value
            );
        }
        _ => {}
    }
}

pub fn flush_engine_iostall_properties(engine: &DB, name: &str) {
    let stall_num = ROCKSDB_IOSTALL_KEY.len();
    let mut counter = vec![0; stall_num];
    for cf in engine.cf_names() {
        let handle = crate::util::get_cf_handle(engine, cf).unwrap();
        if let Some(info) = engine.get_map_property_cf(handle, ROCKSDB_CFSTATS) {
            for i in 0..stall_num {
                let value = info.get_property_int_value(ROCKSDB_IOSTALL_KEY[i]);
                counter[i] += value as i64;
            }
        } else {
            return;
        }
    }
    for i in 0..stall_num {
        STORE_ENGINE_WRITE_STALL_REASON_GAUGE_VEC
            .with_label_values(&[name, ROCKSDB_IOSTALL_TYPE[i]])
            .set(counter[i]);
    }
}

pub fn flush_engine_properties(engine: &DB, name: &str, shared_block_cache: bool) {
    for cf in engine.cf_names() {
        let handle = crate::util::get_cf_handle(engine, cf).unwrap();
        // It is important to monitor each cf's size, especially the "raft" and "lock" column
        // families.
        let cf_used_size = crate::util::get_engine_cf_used_size(engine, handle);
        STORE_ENGINE_SIZE_GAUGE_VEC
            .with_label_values(&[name, cf])
            .set(cf_used_size as i64);

        if !shared_block_cache {
            let block_cache_usage = engine.get_block_cache_usage_cf(handle);
            STORE_ENGINE_BLOCK_CACHE_USAGE_GAUGE_VEC
                .with_label_values(&[name, cf])
                .set(block_cache_usage as i64);
        }

        let blob_cache_usage = engine.get_blob_cache_usage_cf(handle);
        STORE_ENGINE_BLOB_CACHE_USAGE_GAUGE_VEC
            .with_label_values(&[name, cf])
            .set(blob_cache_usage as i64);

        // TODO: find a better place to record these metrics.
        // Refer: https://github.com/facebook/rocksdb/wiki/Memory-usage-in-RocksDB
        // For index and filter blocks memory
        if let Some(readers_mem) = engine.get_property_int_cf(handle, ROCKSDB_TABLE_READERS_MEM) {
            STORE_ENGINE_MEMORY_GAUGE_VEC
                .with_label_values(&[name, cf, "readers-mem"])
                .set(readers_mem as i64);
        }

        // For memtable
        if let Some(mem_table) = engine.get_property_int_cf(handle, ROCKSDB_CUR_SIZE_ALL_MEM_TABLES)
        {
            STORE_ENGINE_MEMORY_GAUGE_VEC
                .with_label_values(&[name, cf, "mem-tables"])
                .set(mem_table as i64);
        }

        // TODO: add cache usage and pinned usage.

        if let Some(num_keys) = engine.get_property_int_cf(handle, ROCKSDB_ESTIMATE_NUM_KEYS) {
            STORE_ENGINE_ESTIMATE_NUM_KEYS_VEC
                .with_label_values(&[name, cf])
                .set(num_keys as i64);
        }

        // Pending compaction bytes
        if let Some(pending_compaction_bytes) =
            engine.get_property_int_cf(handle, ROCKSDB_PENDING_COMPACTION_BYTES)
        {
            STORE_ENGINE_PENDING_COMPACTION_BYTES_VEC
                .with_label_values(&[name, cf])
                .set(pending_compaction_bytes as i64);
        }

        let opts = engine.get_options_cf(handle);
        for level in 0..opts.get_num_levels() {
            // Compression ratio at levels
            if let Some(v) =
                crate::util::get_engine_compression_ratio_at_level(engine, handle, level)
            {
                STORE_ENGINE_COMPRESSION_RATIO_VEC
                    .with_label_values(&[name, cf, &level.to_string()])
                    .set(v);
            }

            // Num files at levels
            if let Some(v) = crate::util::get_cf_num_files_at_level(engine, handle, level) {
                STORE_ENGINE_NUM_FILES_AT_LEVEL_VEC
                    .with_label_values(&[name, cf, &level.to_string()])
                    .set(v as i64);
            }

            // Titan Num blob files at levels
            if let Some(v) = crate::util::get_cf_num_blob_files_at_level(engine, handle, level) {
                STORE_ENGINE_TITANDB_NUM_BLOB_FILES_AT_LEVEL_VEC
                    .with_label_values(&[name, cf, &level.to_string()])
                    .set(v as i64);
            }
        }

        // Num immutable mem-table
        if let Some(v) = crate::util::get_num_immutable_mem_table(engine, handle) {
            STORE_ENGINE_NUM_IMMUTABLE_MEM_TABLE_VEC
                .with_label_values(&[name, cf])
                .set(v as i64);
        }

        // Titan live blob size
        if let Some(v) = engine.get_property_int_cf(handle, ROCKSDB_TITANDB_LIVE_BLOB_SIZE) {
            STORE_ENGINE_TITANDB_LIVE_BLOB_SIZE_VEC
                .with_label_values(&[name, cf])
                .set(v as i64);
        }

        // Titan num live blob file
        if let Some(v) = engine.get_property_int_cf(handle, ROCKSDB_TITANDB_NUM_LIVE_BLOB_FILE) {
            STORE_ENGINE_TITANDB_NUM_LIVE_BLOB_FILE_VEC
                .with_label_values(&[name, cf])
                .set(v as i64);
        }

        // Titan num obsolete blob file
        if let Some(v) = engine.get_property_int_cf(handle, ROCKSDB_TITANDB_NUM_OBSOLETE_BLOB_FILE)
        {
            STORE_ENGINE_TITANDB_NUM_OBSOLETE_BLOB_FILE_VEC
                .with_label_values(&[name, cf])
                .set(v as i64);
        }

        // Titan live blob file size
        if let Some(v) = engine.get_property_int_cf(handle, ROCKSDB_TITANDB_LIVE_BLOB_FILE_SIZE) {
            STORE_ENGINE_TITANDB_LIVE_BLOB_FILE_SIZE_VEC
                .with_label_values(&[name, cf])
                .set(v as i64);
        }

        // Titan obsolete blob file size
        if let Some(v) = engine.get_property_int_cf(handle, ROCKSDB_TITANDB_OBSOLETE_BLOB_FILE_SIZE)
        {
            STORE_ENGINE_TITANDB_OBSOLETE_BLOB_FILE_SIZE_VEC
                .with_label_values(&[name, cf])
                .set(v as i64);
        }

        // Titan blob file discardable ratio
        if let Some(v) =
            engine.get_property_int_cf(handle, ROCKSDB_TITANDB_DISCARDABLE_RATIO_LE0_FILE)
        {
            STORE_ENGINE_TITANDB_BLOB_FILE_DISCARDABLE_RATIO_VEC
                .with_label_values(&[name, cf, "le0"])
                .set(v as i64);
        }
        if let Some(v) =
            engine.get_property_int_cf(handle, ROCKSDB_TITANDB_DISCARDABLE_RATIO_LE20_FILE)
        {
            STORE_ENGINE_TITANDB_BLOB_FILE_DISCARDABLE_RATIO_VEC
                .with_label_values(&[name, cf, "le20"])
                .set(v as i64);
        }
        if let Some(v) =
            engine.get_property_int_cf(handle, ROCKSDB_TITANDB_DISCARDABLE_RATIO_LE50_FILE)
        {
            STORE_ENGINE_TITANDB_BLOB_FILE_DISCARDABLE_RATIO_VEC
                .with_label_values(&[name, cf, "le50"])
                .set(v as i64);
        }
        if let Some(v) =
            engine.get_property_int_cf(handle, ROCKSDB_TITANDB_DISCARDABLE_RATIO_LE80_FILE)
        {
            STORE_ENGINE_TITANDB_BLOB_FILE_DISCARDABLE_RATIO_VEC
                .with_label_values(&[name, cf, "le80"])
                .set(v as i64);
        }
        if let Some(v) =
            engine.get_property_int_cf(handle, ROCKSDB_TITANDB_DISCARDABLE_RATIO_LE100_FILE)
        {
            STORE_ENGINE_TITANDB_BLOB_FILE_DISCARDABLE_RATIO_VEC
                .with_label_values(&[name, cf, "le100"])
                .set(v as i64);
        }
    }

    // For snapshot
    if let Some(n) = engine.get_property_int(ROCKSDB_NUM_SNAPSHOTS) {
        STORE_ENGINE_NUM_SNAPSHOTS_GAUGE_VEC
            .with_label_values(&[name])
            .set(n as i64);
    }
    if let Some(t) = engine.get_property_int(ROCKSDB_OLDEST_SNAPSHOT_TIME) {
        // RocksDB returns 0 if no snapshots.
        let now = time::get_time().sec as u64;
        let d = if t > 0 && now > t { now - t } else { 0 };
        STORE_ENGINE_OLDEST_SNAPSHOT_DURATION_GAUGE_VEC
            .with_label_values(&[name])
            .set(d as i64);
    }

    if shared_block_cache {
        // Since block cache is shared, getting cache size from any CF is fine. Here we get from
        // default CF.
        let handle = crate::util::get_cf_handle(engine, CF_DEFAULT).unwrap();
        let block_cache_usage = engine.get_block_cache_usage_cf(handle);
        STORE_ENGINE_BLOCK_CACHE_USAGE_GAUGE_VEC
            .with_label_values(&[name, "all"])
            .set(block_cache_usage as i64);
    }
}

// For property metrics
#[rustfmt::skip]
lazy_static! {
    pub static ref STORE_ENGINE_SIZE_GAUGE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_size_bytes",
        "Sizes of each column families",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOCK_CACHE_USAGE_GAUGE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_block_cache_size_bytes",
        "Usage of each column families' block cache",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_CACHE_USAGE_GAUGE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_blob_cache_size_bytes",
        "Usage of each column families' blob cache",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_MEMORY_GAUGE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_memory_bytes",
        "Sizes of each column families",
        &["db", "cf", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_ESTIMATE_NUM_KEYS_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_estimate_num_keys",
        "Estimate num keys of each column families",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_PENDING_COMPACTION_BYTES_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_pending_compaction_bytes",
        "Pending compaction bytes",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_COMPRESSION_RATIO_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_compression_ratio",
        "Compression ratio at different levels",
        &["db", "cf", "level"]
    ).unwrap();
    pub static ref STORE_ENGINE_NUM_FILES_AT_LEVEL_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_num_files_at_level",
        "Number of files at each level",
        &["db", "cf", "level"]
    ).unwrap();
    pub static ref STORE_ENGINE_NUM_SNAPSHOTS_GAUGE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_num_snapshots",
        "Number of unreleased snapshots",
        &["db"]
    ).unwrap();
    pub static ref STORE_ENGINE_OLDEST_SNAPSHOT_DURATION_GAUGE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_oldest_snapshot_duration",
        "Oldest unreleased snapshot duration in seconds",
        &["db"]
    ).unwrap();
    pub static ref STORE_ENGINE_WRITE_STALL_REASON_GAUGE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_write_stall_reason",
        "QPS of each reason which cause tikv write stall",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_TITANDB_NUM_BLOB_FILES_AT_LEVEL_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_titandb_num_blob_files_at_level",
        "Number of blob files at each level",
        &["db", "cf", "level"]
    ).unwrap();
    pub static ref STORE_ENGINE_TITANDB_LIVE_BLOB_SIZE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_titandb_live_blob_size",
        "Total titan blob value size referenced by LSM tree",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_TITANDB_NUM_LIVE_BLOB_FILE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_titandb_num_live_blob_file",
        "Number of live blob file",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_TITANDB_NUM_OBSOLETE_BLOB_FILE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_titandb_num_obsolete_blob_file",
        "Number of obsolete blob file",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_TITANDB_LIVE_BLOB_FILE_SIZE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_titandb_live_blob_file_size",
        "Size of live blob file",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_TITANDB_OBSOLETE_BLOB_FILE_SIZE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_titandb_obsolete_blob_file_size",
        "Size of obsolete blob file",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_TITANDB_BLOB_FILE_DISCARDABLE_RATIO_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_titandb_blob_file_discardable_ratio",
        "Size of obsolete blob file",
        &["db", "cf", "ratio"]
    ).unwrap();
}

// For ticker type
#[rustfmt::skip]
lazy_static! {
    pub static ref STORE_ENGINE_CACHE_EFFICIENCY_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_cache_efficiency",
        "Efficiency of rocksdb's block cache",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_CACHE_EFFICIENCY: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_CACHE_EFFICIENCY_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_MEMTABLE_EFFICIENCY_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_memtable_efficiency",
        "Hit and miss of memtable",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_MEMTABLE_EFFICIENCY: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_MEMTABLE_EFFICIENCY_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_GET_SERVED_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_get_served",
        "Get queries served by engine",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_GET_SERVED: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_GET_SERVED_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_WRITE_SERVED_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_write_served",
        "Write queries served by engine",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_WRITE_SERVED: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_WRITE_SERVED_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_BLOOM_EFFICIENCY_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_bloom_efficiency",
        "Efficiency of rocksdb's bloom filter",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOOM_EFFICIENCY: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOOM_EFFICIENCY_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_FLOW_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_flow_bytes",
        "Bytes and keys of read/written",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_FLOW: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_FLOW_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_STALL_MICROS_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_stall_micro_seconds",
        "Stall micros",
        &["db"]
    ).unwrap();
    pub static ref STORE_ENGINE_STALL_MICROS: SimpleEngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_STALL_MICROS_VEC, SimpleEngineTickerMetrics);

    pub static ref STORE_ENGINE_COMPACTION_FLOW_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_compaction_flow_bytes",
        "Bytes of read/written during compaction",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_COMPACTION_FLOW: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_COMPACTION_FLOW_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_COMPACTION_DROP_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_compaction_key_drop",
        "Count the reasons for key drop during compaction",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_COMPACTION_DROP: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_COMPACTION_DROP_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_COMPACTION_DURATIONS_VEC: HistogramVec = register_histogram_vec!(
        "tikv_engine_compaction_duration_seconds",
        "Histogram of compaction duration seconds",
        &["db", "cf"],
        exponential_buckets(0.005, 2.0, 20).unwrap()
    ).unwrap();
    pub static ref STORE_ENGINE_COMPACTION_NUM_CORRUPT_KEYS_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_compaction_num_corrupt_keys",
        "Number of corrupt keys during compaction",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_COMPACTION_REASON_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_compaction_reason",
        "Number of compaction reason",
        &["db", "cf", "reason"]
    ).unwrap();
    pub static ref STORE_ENGINE_LOCATE_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_locate",
        "Number of calls to seek/next/prev",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_LOCATE: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_LOCATE_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_FILE_STATUS_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_file_status",
        "Number of different status of files",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_FILE_STATUS: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_FILE_STATUS_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_READ_AMP_FLOW_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_read_amp_flow_bytes",
        "Bytes of read amplification",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_READ_AMP_FLOW: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_READ_AMP_FLOW_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_NO_ITERATORS: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_no_iterator",
        "Number of iterators currently open",
        &["db"]
    ).unwrap();
    pub static ref STORE_ENGINE_WAL_FILE_SYNCED_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_wal_file_synced",
        "Number of times WAL sync is done",
        &["db"]
    ).unwrap();
    pub static ref STORE_ENGINE_WAL_FILE_SYNCED: SimpleEngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_WAL_FILE_SYNCED_VEC, SimpleEngineTickerMetrics);

    pub static ref STORE_ENGINE_EVENT_COUNTER_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_event_total",
        "Number of engine events",
        &["db", "cf", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_NUM_IMMUTABLE_MEM_TABLE_VEC: IntGaugeVec = register_int_gauge_vec!(
        "tikv_engine_num_immutable_mem_table",
        "Number of immutable mem-table",
        &["db", "cf"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_LOCATE_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_blob_locate",
        "Number of calls to titan blob seek/next/prev",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_LOCATE: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOB_LOCATE_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_BLOB_FLOW_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_blob_flow_bytes",
        "Bytes and keys of titan blob read/written",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_FLOW: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOB_FLOW_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_BLOB_GC_FLOW_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_blob_gc_flow_bytes",
        "Bytes and keys of titan blob gc read/written",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_GC_FLOW: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOB_GC_FLOW_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_BLOB_GC_FILE_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_blob_gc_file_count",
        "Number of blob file involved in titan blob gc",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_GC_FILE: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOB_GC_FILE_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_BLOB_GC_ACTION_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_blob_gc_action_count",
        "Number of actions of titan gc",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_GC_ACTION: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOB_GC_ACTION_VEC, EngineTickerMetrics);

    pub static ref STORE_ENGINE_BLOB_FILE_SYNCED_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_blob_file_synced",
        "Number of times titan blob file sync is done",
        &["db"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_FILE_SYNCED: SimpleEngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOB_FILE_SYNCED_VEC, SimpleEngineTickerMetrics);

    pub static ref STORE_ENGINE_BLOB_CACHE_EFFICIENCY_VEC: IntCounterVec = register_int_counter_vec!(
        "tikv_engine_blob_cache_efficiency",
        "Efficiency of titan's blob cache",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_CACHE_EFFICIENCY: EngineTickerMetrics =
        auto_flush_from!(STORE_ENGINE_BLOB_CACHE_EFFICIENCY_VEC, EngineTickerMetrics);
}

// For histogram type
#[rustfmt::skip]
lazy_static! {
    pub static ref STORE_ENGINE_GET_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_get_micro_seconds",
        "Histogram of get micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_WRITE_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_write_micro_seconds",
        "Histogram of write micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_COMPACTION_TIME_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_compaction_time",
        "Histogram of compaction time",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_TABLE_SYNC_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_table_sync_micro_seconds",
        "Histogram of table sync micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_COMPACTION_OUTFILE_SYNC_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_compaction_outfile_sync_micro_seconds",
        "Histogram of compaction outfile sync micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_MANIFEST_FILE_SYNC_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_manifest_file_sync_micro_seconds",
        "Histogram of manifest file sync micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_WAL_FILE_SYNC_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_wal_file_sync_micro_seconds",
        "Histogram of WAL file sync micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_STALL_L0_SLOWDOWN_COUNT_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_stall_l0_slowdown_count",
        "Histogram of stall l0 slowdown count",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_STALL_MEMTABLE_COMPACTION_COUNT_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_stall_memtable_compaction_count",
        "Histogram of stall memtable compaction count",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_STALL_L0_NUM_FILES_COUNT_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_stall_l0_num_files_count",
        "Histogram of stall l0 num files count",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_HARD_RATE_LIMIT_DELAY_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_hard_rate_limit_delay_count",
        "Histogram of hard rate limit delay count",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_SOFT_RATE_LIMIT_DELAY_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_soft_rate_limit_delay_count",
        "Histogram of soft rate limit delay count",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_NUM_FILES_IN_SINGLE_COMPACTION_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_num_files_in_single_compaction",
        "Histogram of number of files in single compaction",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_SEEK_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_seek_micro_seconds",
        "Histogram of seek micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_WRITE_STALL_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_write_stall",
        "Histogram of write stall",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_SST_READ_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_sst_read_micros",
        "Histogram of SST read micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_NUM_SUBCOMPACTION_SCHEDULED_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_num_subcompaction_scheduled",
        "Histogram of number of subcompaction scheduled",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BYTES_PER_READ_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_bytes_per_read",
        "Histogram of bytes per read",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BYTES_PER_WRITE_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_bytes_per_write",
        "Histogram of bytes per write",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BYTES_COMPRESSED_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_bytes_compressed",
        "Histogram of bytes compressed",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BYTES_DECOMPRESSED_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_bytes_decompressed",
        "Histogram of bytes decompressed",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_COMPRESSION_TIMES_NANOS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_compression_time_nanos",
        "Histogram of compression time nanos",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_DECOMPRESSION_TIMES_NANOS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_decompression_time_nanos",
        "Histogram of decompression time nanos",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_WRITE_WAL_TIME_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_write_wal_time_micro_seconds",
        "Histogram of write wal micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_KEY_SIZE_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_key_size",
        "Histogram of titan blob key size",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_VALUE_SIZE_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_value_size",
        "Histogram of titan blob value size",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_GET_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_get_micros_seconds",
        "Histogram of titan blob read micros for calling get",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_SEEK_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_seek_micros_seconds",
        "Histogram of titan blob read micros for calling seek",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_NEXT_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_next_micros_seconds",
        "Histogram of titan blob read micros for calling next",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_PREV_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_prev_micros_seconds",
        "Histogram of titan blob read micros for calling prev",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_FILE_WRITE_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_file_write_micros_seconds",
        "Histogram of titan blob file write micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_FILE_READ_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_file_read_micros_seconds",
        "Histogram of titan blob file read micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_FILE_SYNC_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_file_sync_micros_seconds",
        "Histogram of titan blob file sync micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_BLOB_GC_MICROS_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_gc_micros_seconds",
        "Histogram of titan blob gc micros",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_GC_INPUT_BLOB_FILE_SIZE_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_gc_input_file",
        "Histogram of titan blob gc input file size",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_GC_OUTPUT_BLOB_FILE_SIZE_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_gc_output_file",
        "Histogram of titan blob gc output file size",
        &["db", "type"]
    ).unwrap();
    pub static ref STORE_ENGINE_ITER_TOUCH_BLOB_FILE_COUNT_VEC: GaugeVec = register_gauge_vec!(
        "tikv_engine_blob_iter_touch_blob_file_count",
        "Histogram of titan iter touched blob file count",
        &["db", "type"]
    ).unwrap();
}

#[cfg(test)]
mod tests {
    use super::*;

    use tempfile::Builder;

    use engine_traits::ALL_CFS;
    use rocksdb::HistogramData;

    #[test]
    fn test_flush() {
        let dir = Builder::new().prefix("test-flush").tempdir().unwrap();
        let engine =
            crate::util::new_engine(dir.path().to_str().unwrap(), None, ALL_CFS, None).unwrap();
        for tp in ENGINE_TICKER_TYPES {
            flush_engine_ticker_metrics(*tp, 2, "kv");
        }

        for tp in ENGINE_HIST_TYPES {
            flush_engine_histogram_metrics(*tp, HistogramData::default(), "kv");
        }

        let shared_block_cache = false;
        flush_engine_properties(&engine.as_inner(), "kv", shared_block_cache);
        let handle = engine.as_inner().cf_handle("default").unwrap();
        let info = engine
            .as_inner()
            .get_map_property_cf(handle, ROCKSDB_CFSTATS);
        assert!(info.is_some());
    }
}


text:
/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
(function () {
  /* global ScheduleStatus:false, JobUpdateKey:false, JobUpdateQuery:false, JobKey:false */
  'use strict';

  /* Controllers */

  var auroraUIControllers = angular.module('auroraUI.controllers', []);

  var infoTableConfig = {
    isGlobalSearchActivated: true,
    isPaginationEnabled: true,
    itemsByPage: 25,
    maxSize: 8,
    selectionMode: 'single'
  };

  var summaryTableConfig = {
    isPaginationEnabled: false,
    isGlobalSearchActivated: false,
    selectionMode: 'none'
  };

  var REFRESH_RATES = {
    IN_PROGRESS_UPDATE_MS: 15000,
    COMPLETED_UPDATES_MS: 60000
  };

  auroraUIControllers.controller('RoleSummaryController',
    function ($scope, auroraClient) {
      $scope.title = 'Scheduled Jobs Summary';

      $scope.error = '';

      auroraClient.getRoleSummary().then(function (roleSummaries) {
        $scope.roleSummaries = parseResponse(roleSummaries);

        $scope.roleSummaryColumns = [
          {label: 'Role', map: 'role', cellTemplateUrl: '/assets/roleLink.html'},
          {label: 'Jobs', map: 'jobCount'},
          {label: 'Cron Jobs', map: 'cronJobCount'}
        ];

        function parseResponse(response) {
          $scope.error = response.error ? 'Error requesting role summary: ' + response.error : '';

          if ($scope.error) {
            return [];
          }

          // TODO(Suman Karumuri): Replace sort with defaultSortColumn once it lands
          // https://github.com/lorenzofox3/Smart-Table/pull/61
          return response.summaries.sort(function (a, b) {
            if (a.role.toLowerCase() > b.role.toLowerCase()) {
              return 1;
            }
            if (a.role.toLowerCase() < b.role.toLowerCase()) {
              return -1;
            }
            return 0;
          });
        }

        $scope.roleSummaryTableConfig = infoTableConfig;
        $scope.roleSummaryTableConfig.columnSpan = $scope.roleSummaryColumns.length;
      });
    });

  auroraUIControllers.controller('JobSummaryController',
    function ($scope, $routeParams, auroraClient) {
      $scope.role = $routeParams.role;
      $scope.environment = $routeParams.environment;

      $scope.error = '';

      $scope.jobsTableColumns = [
        {label: 'Job Type', map: 'jobType'},
        {label: 'Environment', map: 'environment', cellTemplateUrl: '/assets/roleEnvLink.html'},
        {label: 'Job', map: 'jobName', cellTemplateUrl: '/assets/jobLink.html'},
        {label: 'production', map: 'isProduction'},
        {label: 'Pending Tasks', map: 'pendingTasks'},
        {label: 'Active Tasks', map: 'activeTasks'},
        {label: 'Finished Tasks', map: 'finishedTasks'},
        {label: 'Failed Tasks', map: 'failedTasks'}
      ];

      $scope.jobsTableConfig = infoTableConfig;
      $scope.jobsTableConfig.columnSpan = $scope.jobsTableColumns.length;

      function getJobType(job) {
        if (job.taskConfig.isService) {
          return 'service';
        }

        if (job.cronSchedule !== null) {
          return 'cron';
        }

        return 'adhoc';
      }

      function getJobs(summaries) {
        $scope.error = summaries.error ? 'Error fetching job summaries: ' + summaries.error : '';

        if ($scope.error) {
          return [];
        }

        var jobSummaries = summaries.jobs;

        if ($scope.environment) {
          jobSummaries = _.filter(jobSummaries, function (summary) {
            return summary.job.key.environment === $scope.environment;
          });
        }

        var byJobName = function (summary) {
          return summary.jobName;
        };

        return _.chain(jobSummaries)
          .map(function (summary) {
            return {
              role: $scope.role, // required for roleEnvLink directive
              environment: summary.job.key.environment,
              jobName: summary.job.taskConfig.jobName,
              jobType: getJobType(summary.job),
              isProduction: summary.job.taskConfig.production ? 'yes' : '',
              pendingTasks: summary.stats.pendingTaskCount,
              activeTasks: summary.stats.activeTaskCount,
              finishedTasks: summary.stats.finishedTaskCount,
              failedTasks: summary.stats.failedTaskCount
            };
          })
          .sortBy(byJobName)
          .value();
      }

      auroraClient.getJobSummary($scope.role).then(function (summaries) {
        $scope.jobs = getJobs(summaries);
      });

    });

  auroraUIControllers.controller('QuotaController',
    function ($scope, $filter, auroraClient) {
      $scope.error = '';

      $scope.resourcesTableColumns = [
        {label: 'Resource', map: 'resource'},
        {label: 'Production Consumption', map: 'prodConsumption'},
        {label: 'Quota', map: 'quota'},
        {label: 'Non-Production Consumption', map: 'nonProdConsumption'}
      ];

      $scope.resourcesTableConfig = summaryTableConfig;

      auroraClient.getQuota($scope.role).then(function (quotaResponse) {
        $scope.resources = getQuota(quotaResponse);
      });

      function getQuota(quotaResponse) {
        $scope.error = quotaResponse.error ? 'Error fetching quota: ' + quotaResponse.error : '';

        if ($scope.error) {
          return [];
        }

        var consumption = quotaResponse.quota;
        return [
          {
            resource: 'CPU',
            prodConsumption: $filter('toCores')(consumption.prodConsumption.numCpus),
            quota: $filter('toCores')(consumption.quota.numCpus),
            nonProdConsumption: $filter('toCores')(consumption.nonProdConsumption.numCpus)
          },
          {
            resource: 'RAM',
            prodConsumption: $filter('scaleMb')(consumption.prodConsumption.ramMb),
            quota: $filter('scaleMb')(consumption.quota.ramMb),
            nonProdConsumption: $filter('scaleMb')(consumption.nonProdConsumption.ramMb)
          },
          {
            resource: 'Disk',
            prodConsumption: $filter('scaleMb')(consumption.prodConsumption.diskMb),
            quota: $filter('scaleMb')(consumption.quota.diskMb),
            nonProdConsumption: $filter('scaleMb')(consumption.nonProdConsumption.diskMb)
          }
        ];
      }
    }
  );

  auroraUIControllers.controller('CronJobSummaryController',
    function ($scope, $filter, cronJobSummaryService) {
      $scope.cronJobSummaryTableConfig = summaryTableConfig;

      $scope.cronJobSummaryTableColumns = [
        {label: 'Number of tasks', map: 'tasks', isSortable: false},
        {label: 'Cron Schedule', map: 'schedule', isSortable: false},
        {label: 'Next Cron Run', map: 'nextCronRun', isSortable: false},
        {label: 'Collision Policy', map: 'collisionPolicy', isSortable: false},
        {label: 'Metadata', map: 'metadata', isSortable: false}
      ];

      $scope.error = '';
      $scope.cronJobSummary = [];

      cronJobSummaryService.getCronJobSummary($scope.role, $scope.environment,
       $scope.job).then(function (cronJobSummary) {
        if (cronJobSummary.error) {
          $scope.error = 'Error fetching cron job summary: ' + cronJobSummary.error;
          return [];
        }

        if (cronJobSummary.cronJobSummary) {
          var nextCronRunTs = cronJobSummary.cronJobSummary.nextCronRun;
          cronJobSummary.cronJobSummary.nextCronRun =
            $filter('toLocalTime')(nextCronRunTs) + ', ' + $filter('toUtcTime')(nextCronRunTs);

          $scope.cronJobSummary = [cronJobSummary.cronJobSummary];
        }
      });
    }
  );

  auroraUIControllers.controller('AllUpdatesController',
    function ($scope, $timeout, auroraClient, updateUtil) {

      function inProgressUpdates() {
        // fetch any in progress updates
        auroraClient.getJobUpdateSummaries(updateUtil.getInProgressQuery())
          .then(function (response) {
            $scope.inProgressUpdates = response.summaries;
            $timeout(function () { inProgressUpdates(); }, REFRESH_RATES.IN_PROGRESS_UPDATE_MS);
          });
      }

      function completedUpdates() {
        // fetch the latest 20 finished updates
        var finishedQuery = updateUtil.getTerminalQuery();
        finishedQuery.limit = 20;

        auroraClient.getJobUpdateSummaries(finishedQuery).then(function (response) {
          $scope.completedUpdates = response.summaries;
          $timeout(function () { completedUpdates(); }, REFRESH_RATES.COMPLETED_UPDATES_MS);
        });
      }

      inProgressUpdates();
      completedUpdates();
    }
  );

  auroraUIControllers.controller('UpdateController',
    function ($scope, $routeParams, $timeout, auroraClient, updateUtil) {
      var updateKey = new JobUpdateKey();
      updateKey.job = new JobKey();
      updateKey.job.role = $routeParams.role;
      updateKey.job.environment = $routeParams.environment;
      updateKey.job.name = $routeParams.job;
      updateKey.id = $routeParams.update;

      $scope.role = $routeParams.role;
      $scope.environment = $routeParams.environment;
      $scope.job = $routeParams.job;

      $scope.instanceSummary = [];

      var getUpdateProgress = function () {
        auroraClient.getJobUpdateDetails(updateKey).then(function (response) {
          $scope.update = response.details;
          $scope.inProgress = updateUtil.isInProgress($scope.update.update.summary.state.status);

          var duration = $scope.update.update.summary.state.lastModifiedTimestampMs -
            $scope.update.update.summary.state.createdTimestampMs;

          $scope.duration = moment.duration(duration).humanize();

          $scope.stats = updateUtil.getUpdateStats($scope.update);
          $scope.configJson = JSON
            .stringify($scope.update.update.instructions.desiredState.task, undefined, 2);

          // pagination for instance events
          var instanceEvents = $scope.instanceEvents = $scope.update.instanceEvents;
          $scope.eventsPerPage = 10;
          $scope.changeInstancePage = function () {
            var start = ($scope.currentPage - 1) * $scope.eventsPerPage;
            var end   = start + $scope.eventsPerPage;
            $scope.instanceEvents = instanceEvents.slice(start, end);
          };
          $scope.totalEvents = instanceEvents.length;
          $scope.currentPage = 1;
          $scope.changeInstancePage();

          // Instance summary display.
          $scope.instanceSummary = updateUtil.fillInstanceSummary($scope.update, $scope.stats);

          if ($scope.instanceSummary.length <= 20) {
            $scope.instanceGridSize = 'big';
          } else if ($scope.instanceSummary.length <= 1000) {
            $scope.instanceGridSize = 'medium';
          } else {
            $scope.instanceGridSize = 'small';
          }

          // Poll for updates while this update is in progress.
          if ($scope.inProgress) {
            $timeout(function () {
              getUpdateProgress();
            }, REFRESH_RATES.IN_PROGRESS_UPDATE_MS);
          }
        });
      };

      getUpdateProgress();
    }
  );

  auroraUIControllers.controller('JobController',
    function ($scope, $routeParams, $timeout, $q, auroraClient, taskUtil, updateUtil) {
      $scope.error = '';

      $scope.role = $routeParams.role;
      $scope.environment = $routeParams.environment;
      $scope.job = $routeParams.job;

      var taskTableConfig = {
        isGlobalSearchActivated: false,
        isPaginationEnabled: true,
        itemsByPage: 50,
        maxSize: 8,
        selectionMode: 'single'
      };

      $scope.activeTasksTableConfig = taskTableConfig;
      $scope.completedTasksTableConfig = taskTableConfig;

      var taskColumns = [
        {label: 'Instance', map: 'instanceId'},
        {label: 'Status', map: 'status', cellTemplateUrl: '/assets/taskStatus.html'},
        {label: 'Host', map: 'host', cellTemplateUrl: '/assets/taskSandbox.html'}
      ];

      var completedTaskColumns = addColumn(2,
        taskColumns,
        {label: 'Running duration',
          map: 'duration',
          formatFunction: function (duration) {
            return moment.duration(duration).humanize();
          }
        });

      var taskIdColumn = {
        label: 'Task ID',
        map: 'taskId',
        cellTemplateUrl: '/assets/taskLink.html'
      };

      $scope.activeTasksTableColumns = taskColumns;

      $scope.completedTasksTableColumns = completedTaskColumns;

      function addColumn(idxPosition, currentColumns, newColumn) {
        return _.union(
          _.first(currentColumns, idxPosition),
          [newColumn],
          _.last(currentColumns, currentColumns.length - idxPosition));
      }

      $scope.showTaskInfoLink = false;

      $scope.toggleTaskInfoLinkVisibility = function () {
        $scope.showTaskInfoLink = !$scope.showTaskInfoLink;

        $scope.activeTasksTableColumns = $scope.showTaskInfoLink ?
          addColumn(2, taskColumns, taskIdColumn) :
          taskColumns;

        $scope.completedTasksTableColumns = $scope.showTaskInfoLink ?
          addColumn(3, completedTaskColumns, taskIdColumn) :
          completedTaskColumns;
      };

      $scope.jobDashboardUrl = '';
      // These two task arrays need to be initialized due to a quirk in SmartTable's behavior.
      $scope.activeTasks = [];
      $scope.completedTasks = [];
      $scope.tasksReady = false;

      function buildGroupSummary(response) {

        if (response.error) {
          $scope.error = 'Error fetching configuration summary: ' + response.error;
          return [];
        }

        var colors = [
          'steelblue',
          'darkseagreen',
          'sandybrown',
          'plum',
          'khaki'
        ];

        var total = _.reduce(response.groups, function (m, n) {
          return m + n.instanceIds.length;
        }, 0);

        $scope.groupSummary = response.groups.map(function (group, i) {
          var count = group.instanceIds.length;
          var percentage = (count / total) * 100;

          var ranges = taskUtil.toRanges(group.instanceIds).map(function (r) {
            return (r.start === r.end) ? r.start : r.start + '-' + r.end;
          });

          return {
            label: ranges.join(', '),
            value: count,
            percentage: percentage,
            summary: { schedulingDetail: taskUtil.configToDetails(group.config)},
            color: colors[i % colors.length]
          };
        });
      }

      auroraClient.getTasksWithoutConfigs($scope.role, $scope.environment, $scope.job)
        .then(getTasksForJob);

      auroraClient.getConfigSummary($scope.role, $scope.environment, $scope.job)
        .then(buildGroupSummary);

      var query = new JobUpdateQuery();
      var jobKey = new JobKey();
      jobKey.role = $scope.role;
      jobKey.environment = $scope.environment;
      jobKey.name = $scope.job;
      query.jobKey = jobKey;

      auroraClient.getJobUpdateSummaries(query).then(getUpdatesForJob);

      function getUpdatesForJob(response) {
        $scope.updates = response.summaries;

        function getUpdateInProgress() {
          auroraClient.getJobUpdateDetails($scope.updates[0].key).then(function (response) {
            $scope.updateInProgress = response.details;

            $scope.updateStats = updateUtil.getUpdateStats($scope.updateInProgress);

            if (updateUtil.isInProgress($scope.updateInProgress.update.summary.state.status)) {
              // Poll for updates as long as this update is in progress.
              $timeout(function () {
                getUpdateInProgress();
              }, REFRESH_RATES.IN_PROGRESS_UPDATE_MS);
            }
          });
        }

        if ($scope.updates.length > 0 && updateUtil.isInProgress($scope.updates[0].state.status)) {
          getUpdateInProgress();
        }
      }

      function getTasksForJob(response) {
        if (response.error) {
          $scope.error = 'Error fetching tasks: ' + response.error;
          return [];
        }

        $scope.jobDashboardUrl = getJobDashboardUrl(response.statsUrlPrefix);

        var tasks = _.map(response.tasks, function (task) {
          return summarizeTask(task);
        });

        var activeTaskPredicate = function (task) {
          return task.isActive;
        };

        $scope.activeTasks = _.chain(tasks)
          .filter(activeTaskPredicate)
          .sortBy('instanceId')
          .value();

        $scope.completedTasks = _.chain(tasks)
          .reject(activeTaskPredicate)
          .sortBy(function (task) {
            return -task.latestActivity; //sort in descending order
          })
          .value();

        $scope.tasksReady = true;
      }

      function summarizeTask(task) {
        var isActive = taskUtil.isActiveTask(task);
        var sortedTaskEvents = _.sortBy(task.taskEvents, function (taskEvent) {
          return taskEvent.timestamp;
        });

        var latestTaskEvent = _.last(sortedTaskEvents);

        return {
          instanceId: task.assignedTask.instanceId,
          status: _.invert(ScheduleStatus)[latestTaskEvent.status],
          statusMessage: latestTaskEvent.message,
          host: task.assignedTask.slaveHost || '',
          latestActivity: _.isEmpty(sortedTaskEvents) ? 0 : latestTaskEvent.timestamp,
          duration: getDuration(sortedTaskEvents),
          isActive: isActive,
          taskId: task.assignedTask.taskId,
          taskEvents: summarizeTaskEvents(sortedTaskEvents),
          showDetails: false,
          // TODO(maxim): Revisit this approach when the UI fix in AURORA-715 is finalized.
          sandboxExists: true
        };
      }

      function getDuration(sortedTaskEvents) {
        var runningTaskEvent = _.find(sortedTaskEvents, function (taskEvent) {
          return taskEvent.status === ScheduleStatus.RUNNING;
        });

        if (runningTaskEvent) {
          var nextEvent = sortedTaskEvents[_.indexOf(sortedTaskEvents, runningTaskEvent) + 1];

          return nextEvent ?
            nextEvent.timestamp - runningTaskEvent.timestamp :
            moment().valueOf() - runningTaskEvent.timestamp;
        }

        return 0;
      }

      function summarizeTaskEvents(taskEvents) {
        return _.map(taskEvents, function (taskEvent) {
          return {
            timestamp: taskEvent.timestamp,
            status: _.invert(ScheduleStatus)[taskEvent.status],
            message: taskEvent.message
          };
        });
      }

      function getJobDashboardUrl(statsUrlPrefix) {
        return _.isEmpty(statsUrlPrefix) ?
          '' :
          statsUrlPrefix + $scope.role + '.' + $scope.environment + '.' + $scope.job;
      }
    }
  );
})();

redpajama_set_name: RedPajamaGithub


text:
using System;
using System.Collections.Generic;
using System.Text;

using Muscularity.Core.Shared;
using TypeLite;

namespace Muscularity.Features.Workouts.SaveWorkoutLog
{
    public class SaveWorkoutLogResponse
    {
        public WorkoutLogViewModel WorkoutLog { get; set; }

        public class WorkoutLogViewModel
        {
            public int WorkoutLogId { get; set; }

            public decimal Weight { get; set; }

            public short Reps { get; set; }

            public short RepsInReserve { get; set; }

            public int WorkoutDetailId { get; set; }

            public DateTime CreateDate { get; set; }
        }
    }
}


text:
<?php
namespace Helper;

class Acceptance extends \Codeception\Module
{
    public function seePageHasElement($element)
    {
        try {
            $this->getModule('WebDriver')->_findElements($element);
        } catch (\PHPUnit_Framework_AssertionFailedError $f) {
            return false;
        }
        return true;
    }

    public function clickOnElement($element)
    {
        $this->getModule('WebDriver')->_findElements($element)[0]->click();
    }

    public function getElementText($element)
    {
        return $this->getModule('WebDriver')->_findElements($element)[0]->getText();
    }

    public function getTitle()
    {
        return $this->getModule('WebDriver')->webDriver->getTitle();
    }

    public function sendKeys($string)
    {
        $this->getModule('WebDriver')->webDriver->getKeyboard()->sendKeys($string);
    }
}


text:
:tocdepth: 1

Contributing to COT
===================

.. include:: ../CONTRIBUTING.rst


text:
(function(App) {
    "use strict";

    var Klass = App.views.SelectView = Backbone.View.extend({
        tagName: 'select',

        events: {
            change: function() {
                this.trigger('change', this.value());
            }
        },

        render: function() {
            var self = this;
            var select = this.$el;

            this.options.forEach(function(pair) {
                var value = pair[0];
                var text = pair[1];
                var option = self.make('option', { value: value }, _.escape(text));
                select.append(option);
            });

            return this;
        },

        value: function() {
            return this.$el.val();
        }
    });

    Klass.create = function(options) {
        var view = new Klass();
        view.options = options;
        return view;
    };

}(App));


text:
<?php
/**
 * Logos public part.
 */

// File Security Check
if ( ! defined( 'ABSPATH' ) ) { exit; }

class Presscore_Mod_Logos_Public {

	public function register_shortcodes() {
		foreach ( array( 'logos' ) as $shortcode_name ) {
			include_once plugin_dir_path( __FILE__ ) . "shortcodes/{$shortcode_name}/{$shortcode_name}.php";
		}
	}

	public function load_shortcodes_vc_bridge() {
		include_once plugin_dir_path( __FILE__ ) . "shortcodes/mod-logos-shortcodes-bridge.php";
	}

	public function init_widgets() {
		register_widget( 'Presscore_Inc_Widgets_Logos' );
	}
}


text:
package bridge;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.bridge.SLF4JBridgeHandler;

/**
 * Java Util Logging over SLF4J bridge. Simple activator that takes care of installing
 * the JUL bridge to SLF4J. This because Faces for example, as a Sun-originated solution,
 * uses standard Java logging.
 */
public class Activator implements BundleActivator {
    @Override
    public void start(BundleContext ctx) {
        SLF4JBridgeHandler.removeHandlersForRootLogger();
        SLF4JBridgeHandler.install();
    }

    @Override
    public void stop(BundleContext ctx) {
        SLF4JBridgeHandler.uninstall();
    }
}


text:
package org.qi4j.api.mixin.partial;

// START SNIPPET: partial
public interface SpeedLocation
{
    void turn(float angle);

    void accelerate(float acceleration);
}
// END SNIPPET: partial