Skip to content

Commit

Permalink
Merge pull request #231 from pstout/pds-dynamic-ids
Browse files Browse the repository at this point in the history
Add support for Ids that have dynamically commuted tag values.
  • Loading branch information
brharrington committed Oct 28, 2015
2 parents c67aa45 + 9570ca6 commit 7e282fe
Show file tree
Hide file tree
Showing 31 changed files with 1,799 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright 2015 Netflix, Inc.
*
* 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.
*/
package com.netflix.spectator.api;

import java.util.function.Function;

/**
* Base class for dynamic meters that provides implementations for the core
* interface methods.
*/
abstract class AbstractDefaultDynamicMeter<T extends Meter> implements Meter {
private final DynamicId id;
private final Function<Id, T> meterResolver;

/**
* Creates a new dynamic meter.
*
* @param id the dynamic id for the meter
* @param meterResolver the function to map a resolved id to concrete metric
*/
AbstractDefaultDynamicMeter(DynamicId id, Function<Id, T> meterResolver) {
this.id = id;
this.meterResolver = meterResolver;
}

/**
* Resolve the dynamic id to the current metric instance.
*/
protected final T resolveToCurrentMeter() {
return meterResolver.apply(id.resolveToId());
}

@Override
public final Id id() {
return resolveToCurrentMeter().id();
}

@Override
public final Iterable<Measurement> measure() {
return resolveToCurrentMeter().measure();
}

@Override
public final boolean hasExpired() {
// Without tracking all of the regular meters that are created from this
// dynamic meter we don't have any way of knowing whether the "master"
// counter has expired. Instead of adding the tracking, we choose to
// rely on the regular expiration mechanism for the underlying meters.
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public AbstractRegistry(Clock clock) {
}

@Override public final Id createId(String name) {
return new DefaultId(name, TagList.EMPTY);
return new DefaultId(name);
}

@Override public final Id createId(String name, Iterable<Tag> tags) {
Expand Down Expand Up @@ -104,7 +104,7 @@ private Meter compute(Meter m, Meter fallback) {
@Override public final void register(Meter meter) {
Meter aggr = (meters.size() >= Config.maxNumberOfMeters())
? meters.get(meter.id())
: meters.computeIfAbsent(meter.id(), id -> new AggrMeter(id));
: meters.computeIfAbsent(meter.id(), AggrMeter::new);
if (aggr != null) {
addToAggr(aggr, meter);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Copyright 2015 Netflix, Inc.
*
* 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.
*/
package com.netflix.spectator.api;

import com.netflix.spectator.impl.Preconditions;

/**
* Basic container for Tag data.
*
* Created on 10/1/15.
*/
public final class BasicTag implements Tag {
private final String key;
private final String value;
private final int hc;

/**
* Construct a new instance.
*
* @param key
* @param value
*/
public BasicTag(String key, String value) {
this.key = Preconditions.checkNotNull(key, "key");
this.value = Preconditions.checkNotNull(value, "value");
this.hc = 31 * key.hashCode() + value.hashCode();
}

@Override
public String key() {
return key;
}

@Override
public String value() {
return value;
}

@Override public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || !(obj instanceof BasicTag)) return false;
BasicTag other = (BasicTag) obj;
return key.equals(other.key) && value.equals(other.value);
}

/**
* This object is immutable and the hash code is precomputed in the constructor. The id object
* is typically created to lookup a Meter based on dynamic dimensions so we assume that it is
* highly likely that the hash code method will be called and that it could be in a fairly
* high volume execution path.
*
* {@inheritDoc}
*/
@Override public int hashCode() {
return hc;
}

@Override
public String toString() {
return key + '=' + value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Copyright 2015 Netflix, Inc.
*
* 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.
*/
package com.netflix.spectator.api;

import com.netflix.spectator.impl.Preconditions;

/**
* TagFactory implementation that always produces the same tag. Useful for
* providing a default value for a tag.
*/
public final class ConstantTagFactory implements TagFactory {
private final Tag tag;

/**
* Construct a new instance that will always return a Tag with the specified value.
*
* @param key
* the non-null key for the tag
* @param value
* the non-null value for the tag
*/
public ConstantTagFactory(String key, String value) {
this(new TagList(key, value));
}

/**
* Construct a new instance that will always return the specified tag.
*
* @param tag
* the non-null Tag instance to return from createTag
*/
public ConstantTagFactory(Tag tag) {
this.tag = Preconditions.checkNotNull(tag, "tag");
}

@Override
public String name() {
return tag.key();
}

@Override
public Tag createTag() {
return tag;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.netflix.spectator.api;

/**
* Counter implementation that delegates the value tracking to component counters
* based on the current value of the tags associated with the DynamicId when the
* increment methods are called.
*/
class DefaultDynamicCounter extends AbstractDefaultDynamicMeter<Counter> implements Counter {
/**
* Constructs a new counter with the specified dynamic id.
*
* @param id the dynamic (template) id for generating the individual counters
* @param registry the registry to use to instantiate the individual counters
*/
DefaultDynamicCounter(DynamicId id, Registry registry) {
super(id, registry::counter);
}

@Override
public void increment() {
resolveToCurrentMeter().increment();
}

@Override
public void increment(long amount) {
resolveToCurrentMeter().increment(amount);
}

@Override
public long count() {
return resolveToCurrentMeter().count();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright 2015 Netflix, Inc.
*
* 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.
*/
package com.netflix.spectator.api;

/**
* Distribution summary implementation that delegates the value tracking to
* component distribution summaries based on the current value of the tags
* associated with the DynamicId when the interface methods are called.
*/
class DefaultDynamicDistributionSummary extends AbstractDefaultDynamicMeter<DistributionSummary>
implements DistributionSummary {
/**
* Constructs a new distribution summary with the specified dynamic id.
*
* @param id the dynamic (template) id for generating the individual distribution summaries
* @param registry the registry to use to instantiate the individual distribution summaries
*/
DefaultDynamicDistributionSummary(DynamicId id, Registry registry) {
super(id, registry::distributionSummary);
}

@Override
public void record(long amount) {
resolveToCurrentMeter().record(amount);
}

@Override
public long count() {
return resolveToCurrentMeter().count();
}

@Override
public long totalAmount() {
return resolveToCurrentMeter().totalAmount();
}
}
Loading

0 comments on commit 7e282fe

Please sign in to comment.