anchor.diff:  %%
   %% TCP Connection Monitor
   %%
  -%% Copyright (c) 2013 Basho Technologies, Inc.  All Rights Reserved.
  +%% Copyright (c) 2013-2016 Basho Technologies, Inc.  All Rights Reserved.
   %%
   %% This file is provided to you under the Apache License,
   %% Version 2.0 (the "License"); you may not use this file
  
positive.code: -record(state, {conns = gb_trees:empty(),      % conn records keyed by Socket
                  tags = gb_trees:empty(),       % tags to ports
                  interval = ?DEFAULT_INTERVAL,  % how often to get stats
                  limit = ?DEFAULT_LIMIT,        % 
                  clear_after = ?DEFAULT_CLEAR,  % how long to leave errored sockets in status
                  stats = ?INET_STATS,           % Stats to read
                  opts  = ?INET_OPTS,            % Opts to read
  
negative.code: handle_info(measurement_tick, State0 = #state{limit = Limit, stats = Stats,
                                               opts = Opts, conns = Conns}) ->
      State = schedule_tick(State0),
      UpdateConn = fun
          (_, Conn = #conn{type = error}) ->
              Conn;
          (Socket, Conn = #conn{ts_hist = TSHist, hist = Hist}) ->
              try
                  RawSock = unwrap_socket(Socket),
                  {ok, StatVals} = inet:getstat(RawSock, Stats),
                  % get the timestamp between stats and opts, split the difference
                  TS = os:timestamp(),
                  {ok, OptVals} = inet:getopts(RawSock, Opts),
                  NewHist = update_hist(OptVals, Limit,
                      update_hist(StatVals, Limit, Hist)),
                  Conn#conn{
                      ts_hist = prepend_trunc(TS, TSHist, Limit), hist = NewHist}
              catch
                  _E:_R ->
                      %io:format("Error ~p: ~p\n", [_E, _R]),
                      %% Any problems with getstat/getopts mark in error
                      erlang:send_after(
                          State#state.clear_after, self(), {clear, Socket}),
                      Conn#conn{type = error}
              end
      end,
      {noreply, State#state{conns = gb_trees:map(UpdateConn, Conns)}};
  
  handle_info({clear, Socket}, State = #state{conns = Conns}) ->
      {noreply, State#state{conns = gb_trees:delete_any(Socket, Conns)}}.
  
  %%
  %% The #sslsocket record type definition is invisible outside the ssl
  %% application code (and barely defined inside it), so validate it roughly
  %% the way erlang:is_record/2 would, by checking its type, size, and first
  %% element.
  %% The second element's first element is actually a transport module, but
  %% gen_tcp gets special handling, and is the only type we support anyway.
  %% Anything else will throw a badarg error, causing the connection to be
  %% flagged in error.
  %%
  unwrap_socket(Socket) when erlang:is_tuple(Socket)
          andalso erlang:tuple_size(Socket) > 1
          andalso erlang:element(1, Socket) == sslsocket ->
      TcpSock = erlang:element(2, Socket),
      if  erlang:is_tuple(TcpSock)
          andalso erlang:tuple_size(TcpSock) > 1
          andalso erlang:element(1, TcpSock) == gen_tcp ->
              erlang:element(2, TcpSock);
          true ->
              erlang:error(badarg, [Socket])
      end;
  %%
  %% Anything else gets passed through as-is, let the consumer(s) handle it.
  %%
  unwrap_socket(Socket) ->
      Socket.
  
  terminate(_Reason, _State) ->
      lager:info("Shutting down TCP Monitor"),
  