@Override
  public void onEvent(final RequestEvent event) {
    if (event.getType() == RequestEvent.Type.FINISHED) {
      if (!event.getUriInfo().getMatchedTemplates().isEmpty()) {
        final List<Tag> tags = new ArrayList<>(5);
        tags.add(Tag.of(PATH_TAG, UriInfoUtil.getPathTemplate(event.getUriInfo())));
        tags.add(Tag.of(METHOD_TAG, event.getContainerRequest().getMethod()));
        tags.add(Tag.of(STATUS_CODE_TAG, String.valueOf(Optional
            .ofNullable(event.getContainerResponse())
            .map(ContainerResponse::getStatus)
            .orElse(499))));
        tags.add(Tag.of(TRAFFIC_SOURCE_TAG, trafficSource.name().toLowerCase()));

        @Nullable final String userAgent;
        {
          final List<String> userAgentValues = event.getContainerRequest().getRequestHeader(HttpHeaders.USER_AGENT);
          userAgent = userAgentValues != null && !userAgentValues.isEmpty() ? userAgentValues.get(0) : null;
        }

        tags.add(UserAgentTagUtil.getPlatformTag(userAgent));

        meterRegistry.counter(REQUEST_COUNTER_NAME, tags).increment();

        UserAgentTagUtil.getClientVersionTag(userAgent, clientReleaseManager)
            .ifPresent(clientVersionTag -> meterRegistry.counter(REQUESTS_BY_VERSION_COUNTER_NAME,
                    Tags.of(clientVersionTag, UserAgentTagUtil.getPlatformTag(userAgent)))
                .increment());
      }
    }
  }
@Test
  @SuppressWarnings("unchecked")
  void testOnEvent() {
    final String path = "/test";
    final String method = "GET";
    final int statusCode = 200;

    final ExtendedUriInfo uriInfo = mock(ExtendedUriInfo.class);
    when(uriInfo.getMatchedTemplates()).thenReturn(Collections.singletonList(new UriTemplate(path)));

    final ContainerRequest request = mock(ContainerRequest.class);
    when(request.getMethod()).thenReturn(method);
    when(request.getRequestHeader(HttpHeaders.USER_AGENT)).thenReturn(
        Collections.singletonList("Signal-Android/4.53.7 (Android 8.1)"));

    final ContainerResponse response = mock(ContainerResponse.class);
    when(response.getStatus()).thenReturn(statusCode);

    final RequestEvent event = mock(RequestEvent.class);
    when(event.getType()).thenReturn(RequestEvent.Type.FINISHED);
    when(event.getUriInfo()).thenReturn(uriInfo);
    when(event.getContainerRequest()).thenReturn(request);
    when(event.getContainerResponse()).thenReturn(response);

    final ArgumentCaptor<Iterable<Tag>> tagCaptor = ArgumentCaptor.forClass(Iterable.class);
    when(meterRegistry.counter(eq(MetricsRequestEventListener.REQUEST_COUNTER_NAME), any(Iterable.class)))
        .thenReturn(counter);

    listener.onEvent(event);

    verify(meterRegistry).counter(eq(MetricsRequestEventListener.REQUEST_COUNTER_NAME), tagCaptor.capture());

    final Iterable<Tag> tagIterable = tagCaptor.getValue();
    final Set<Tag> tags = new HashSet<>();

    for (final Tag tag : tagIterable) {
      tags.add(tag);
    }

    assertEquals(5, tags.size());
    assertTrue(tags.contains(Tag.of(MetricsRequestEventListener.PATH_TAG, path)));
    assertTrue(tags.contains(Tag.of(MetricsRequestEventListener.METHOD_TAG, method)));
    assertTrue(tags.contains(Tag.of(MetricsRequestEventListener.STATUS_CODE_TAG, String.valueOf(statusCode))));
    assertTrue(tags.contains(Tag.of(MetricsRequestEventListener.TRAFFIC_SOURCE_TAG, TRAFFIC_SOURCE.name().toLowerCase())));
    assertTrue(tags.contains(Tag.of(UserAgentTagUtil.PLATFORM_TAG, "android")));
  }