code: package io.ray.runtime.metric;
  
  import com.google.common.base.MoreObjects;
  import java.util.Map;
  import java.util.Objects;
  
  /**
   * MetricId represents a metric with a given type, name and tags. If two metrics have the same type
   * and name but different tags(including key and value), they have a different MetricId. And in this
   * way, {@link MetricRegistry} can register two metrics with same name but different tags.
   */
  public class MetricId {
  
    private final MetricType type;
    private final String name;
    private final Map<TagKey, String> tags;
  
    public MetricId(MetricType type, String name, Map<TagKey, String> tags) {
      this.type = type;
      this.name = name;
      this.tags = tags;
    }
  
    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (!(o instanceof MetricId)) {
        return false;
      }
      MetricId metricId = (MetricId) o;
      return type == metricId.type
          && Objects.equals(name, metricId.name)
          && Objects.equals(tags, metricId.tags);
    }
  
    @Override
    public int hashCode() {
      return Objects.hash(type, name, tags);
    }
  
    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this)
          .add("type", type)
          .add("name", name)
          .add("tags", tags)
          .toString();
    }
  
    public MetricType getType() {
      return type;
    }
  
    public String getName() {
      return name;
    }
  
    public Map<TagKey, String> getTags() {
      return tags;
    }
  }
  