PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main/java/org/graylog2/buffers/processors/OutputBufferProcessor.java

http://github.com/Graylog2/graylog2-server
Java | 154 lines | 101 code | 28 blank | 25 comment | 10 complexity | 0c2f698eef29b83b8e76f4d09813cdd4 MD5 | raw file
Possible License(s): GPL-3.0
  1. /**
  2. * Copyright 2012 Lennart Koopmann <lennart@socketfeed.com>
  3. *
  4. * This file is part of Graylog2.
  5. *
  6. * Graylog2 is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Graylog2 is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Graylog2. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. package org.graylog2.buffers.processors;
  21. import com.google.common.collect.Lists;
  22. import com.google.common.util.concurrent.ThreadFactoryBuilder;
  23. import com.lmax.disruptor.EventHandler;
  24. import com.yammer.metrics.Metrics;
  25. import com.yammer.metrics.core.Histogram;
  26. import com.yammer.metrics.core.Meter;
  27. import org.slf4j.Logger;
  28. import org.slf4j.LoggerFactory;
  29. import org.graylog2.Core;
  30. import org.graylog2.buffers.LogMessageEvent;
  31. import org.graylog2.plugin.outputs.MessageOutput;
  32. import org.graylog2.plugin.logmessage.LogMessage;
  33. import java.util.List;
  34. import java.util.Map;
  35. import java.util.concurrent.ExecutorService;
  36. import java.util.concurrent.LinkedBlockingQueue;
  37. import java.util.concurrent.ThreadPoolExecutor;
  38. import java.util.concurrent.TimeUnit;
  39. import org.bson.types.ObjectId;
  40. import org.elasticsearch.common.collect.Maps;
  41. import org.graylog2.outputs.ElasticSearchOutput;
  42. import org.graylog2.outputs.OutputRouter;
  43. import org.graylog2.outputs.OutputStreamConfigurationImpl;
  44. import org.graylog2.plugin.outputs.OutputStreamConfiguration;
  45. import org.graylog2.plugin.streams.Stream;
  46. import org.graylog2.streams.StreamImpl;
  47. /**
  48. * @author Lennart Koopmann <lennart@socketfeed.com>
  49. */
  50. public class OutputBufferProcessor implements EventHandler<LogMessageEvent> {
  51. private static final Logger LOG = LoggerFactory.getLogger(OutputBufferProcessor.class);
  52. private final ExecutorService executor;
  53. private Core server;
  54. private List<LogMessage> buffer = Lists.newArrayList();
  55. private final Meter incomingMessages = Metrics.newMeter(OutputBufferProcessor.class, "IncomingMessages", "messages", TimeUnit.SECONDS);
  56. private final Histogram batchSize = Metrics.newHistogram(OutputBufferProcessor.class, "BatchSize");
  57. private final long ordinal;
  58. private final long numberOfConsumers;
  59. public OutputBufferProcessor(Core server, final long ordinal, final long numberOfConsumers) {
  60. this.ordinal = ordinal;
  61. this.numberOfConsumers = numberOfConsumers;
  62. this.server = server;
  63. executor = new ThreadPoolExecutor(
  64. server.getConfiguration().getOutputBufferProcessorThreadsCorePoolSize(),
  65. server.getConfiguration().getOutputBufferProcessorThreadsMaxPoolSize(),
  66. 5, TimeUnit.SECONDS,
  67. new LinkedBlockingQueue<Runnable>(),
  68. new ThreadFactoryBuilder()
  69. .setNameFormat("outputbuffer-processor-" + ordinal + "-executor-%d")
  70. .build());
  71. }
  72. @Override
  73. public void onEvent(LogMessageEvent event, long sequence, boolean endOfBatch) throws Exception {
  74. // Because Trisha said so. (http://code.google.com/p/disruptor/wiki/FrequentlyAskedQuestions)
  75. if ((sequence % numberOfConsumers) != ordinal) {
  76. return;
  77. }
  78. server.outputBufferWatermark().decrementAndGet();
  79. incomingMessages.mark();
  80. LogMessage msg = event.getMessage();
  81. LOG.debug("Processing message <{}> from OutputBuffer.", msg.getId());
  82. buffer.add(msg);
  83. if (endOfBatch || buffer.size() >= server.getConfiguration().getOutputBatchSize()) {
  84. for (final MessageOutput output : server.getOutputs()) {
  85. final String typeClass = output.getClass().getCanonicalName();
  86. // Always write to ElasticSearch, but only write to other outputs if enabled for one of its streams.
  87. if (output instanceof ElasticSearchOutput || OutputRouter.checkRouting(typeClass, msg)) {
  88. try {
  89. // We must copy the buffer for this output, because it may be cleared before all messages are handled.
  90. final List<LogMessage> myBuffer = Lists.newArrayList(buffer);
  91. LOG.debug("Writing message batch to [{}]. Size <{}>", output.getName(), buffer.size());
  92. batchSize.update(buffer.size());
  93. executor.submit(new Runnable() {
  94. @Override
  95. public void run() {
  96. try {
  97. output.write(myBuffer, buildStreamConfigs(myBuffer, typeClass), server);
  98. } catch (Exception e) {
  99. throw new RuntimeException(e);
  100. }
  101. }
  102. });
  103. } catch (Exception e) {
  104. LOG.error("Could not write message batch to output [" + output.getName() +"].", e);
  105. }
  106. }
  107. }
  108. buffer.clear();
  109. }
  110. LOG.debug("Wrote message <{}> to all outputs. Finished handling.", msg.getId());
  111. }
  112. private OutputStreamConfiguration buildStreamConfigs(List<LogMessage> messages, String className) {
  113. OutputStreamConfiguration configs = new OutputStreamConfigurationImpl();
  114. Map<ObjectId, Stream> distinctStreams = Maps.newHashMap();
  115. for (LogMessage message : messages) {
  116. for (Stream stream : message.getStreams()) {
  117. distinctStreams.put(stream.getId(), stream);
  118. }
  119. }
  120. for (Map.Entry<ObjectId, Stream> e : distinctStreams.entrySet()) {
  121. StreamImpl stream = (StreamImpl) e.getValue();
  122. configs.add(e.getKey(), stream.getOutputConfigurations(className));
  123. }
  124. return configs;
  125. }
  126. }