code: @SuppressWarnings("unchecked")
      public <T extends IMetric> T registerMetric(String name, T metric, int timeBucketSizeInSecs) {
          if ((Boolean) _openOrPrepareWasCalled.deref()) {
              throw new RuntimeException("TopologyContext.registerMetric can only be called from within overridden "
                      + "IBolt::prepare() or ISpout::open() method.");
          }
  
          if (metric == null) {
              throw new IllegalArgumentException("Cannot register a null metric");
          }
  
          if (timeBucketSizeInSecs <= 0) {
              throw new IllegalArgumentException("TopologyContext.registerMetric can only be called with timeBucketSizeInSecs "
                      + "greater than or equal to 1 second.");
          }
  
          if (getRegisteredMetricByName(name) != null) {
              throw new RuntimeException("The same metric name `" + name + "` was registered twice.");
          }
  
          Map m1 = _registeredMetrics;
          if (!m1.containsKey(timeBucketSizeInSecs)) {
              m1.put(timeBucketSizeInSecs, new HashMap());
          }
  
          Map m2 = (Map) m1.get(timeBucketSizeInSecs);
          if (!m2.containsKey(_taskId)) {
              m2.put(_taskId, new HashMap());
          }
  
          Map m3 = (Map) m2.get(_taskId);
          if (m3.containsKey(name)) {
              throw new RuntimeException("The same metric name `" + name + "` was registered twice.");
          } else {
              m3.put(name, metric);
          }
  
          return metric;
      }
docs: /*
  Register a IMetric instance. Storm will then call getValueAndReset on the metric every timeBucketSizeInSecs and the returned value is sent to all metrics
  consumers. You must call this during IBolt::prepare or ISpout::open.
  
  @return The IMetric argument unchanged.