/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.blur.trace.hdfs; import static org.apache.blur.utils.BlurConstants.BLUR_HDFS_TRACE_PATH; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.apache.blur.BlurConfiguration; import org.apache.blur.log.Log; import org.apache.blur.log.LogFactory; import org.apache.blur.trace.Trace.TraceId; import org.apache.blur.trace.TraceCollector; import org.apache.blur.trace.TraceStorage; import org.apache.commons.io.IOUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.json.JSONException; import org.json.JSONObject; public class HdfsTraceStorage extends TraceStorage { private final static Log LOG = LogFactory.getLog(HdfsTraceStorage.class); private Path _storePath; private BlockingQueue<TraceCollector> _queue = new LinkedBlockingQueue<TraceCollector>(); private Thread _daemon; private FileSystem _fileSystem; public HdfsTraceStorage(BlurConfiguration configuration) throws IOException { super(configuration); } public void init(Configuration conf) throws IOException { _storePath = new Path(_configuration.get(BLUR_HDFS_TRACE_PATH)); _fileSystem = _storePath.getFileSystem(conf); _fileSystem.mkdirs(_storePath); _daemon = new Thread(new Runnable() { @Override public void run() { Random random = new Random(); while (true) { TraceCollector collector; try { collector = _queue.take(); } catch (InterruptedException e) { return; } try { writeCollector(collector, random); } catch (Throwable t) { LOG.error("Unknown error while trying to write collector.", t); } } } }); _daemon.setDaemon(true); _daemon.setName("ZooKeeper Trace Queue Writer"); _daemon.start(); } @Override public void store(TraceCollector collector) { try { _queue.put(collector); } catch (InterruptedException e) { LOG.error("Unknown error while trying to add collector on queue", e); } } private void writeCollector(TraceCollector collector, Random random) throws IOException { TraceId id = collector.getId(); String storeId = id.getRootId(); String requestId = id.getRequestId(); if (requestId == null) { requestId = ""; } Path tracePath = getTracePath(storeId); JSONObject jsonObject; try { jsonObject = collector.toJsonObject(); } catch (JSONException e) { throw new IOException(e); } storeJson(new Path(tracePath, getRequestIdPathName(requestId, random)), jsonObject); } private String getRequestIdPathName(String requestId, Random random) { return requestId + "_" + random.nextLong(); } public void storeJson(Path storePath, JSONObject jsonObject) throws IOException { FSDataOutputStream outputStream = _fileSystem.create(storePath, false); try { OutputStreamWriter writer = new OutputStreamWriter(outputStream); jsonObject.write(writer); writer.close(); } catch (JSONException e) { throw new IOException(e); } } private Path getTracePath(String traceId) { return new Path(_storePath, traceId); } @Override public void close() throws IOException { _fileSystem.close(); } @Override public List<String> getTraceIds() throws IOException { FileStatus[] listStatus = _fileSystem.listStatus(_storePath); List<String> traceIds = new ArrayList<String>(); for (FileStatus status : listStatus) { traceIds.add(status.getPath().getName()); } return traceIds; } @Override public List<String> getRequestIds(String traceId) throws IOException { List<String> requestIds = new ArrayList<String>(); Path tracePath = getTracePath(traceId); FileStatus[] listStatus = _fileSystem.listStatus(tracePath); for (FileStatus status : listStatus) { String name = status.getPath().getName(); int indexOf = name.lastIndexOf('_'); if (indexOf > 0) { requestIds.add(name.substring(0, indexOf)); } } return requestIds; } @Override public String getRequestContentsJson(String traceId, String requestId) throws IOException { Path path = findPath(traceId, requestId); FSDataInputStream inputStream = _fileSystem.open(path); try { return IOUtils.toString(inputStream); } finally { inputStream.close(); } } private Path findPath(String traceId, String requestId) throws IOException { Path tracePath = getTracePath(traceId); if (!_fileSystem.exists(tracePath)) { throw new IOException("Trace [" + traceId + "] not found."); } FileStatus[] listStatus = _fileSystem.listStatus(tracePath); for (FileStatus status : listStatus) { Path path = status.getPath(); String name = path.getName(); int indexOf = name.lastIndexOf('_'); if (indexOf > 0) { if (name.substring(0, indexOf).equals(requestId)) { return path; } } } throw new IOException("Request [" + requestId + "] not found."); } @Override public void removeTrace(String traceId) throws IOException { Path storePath = getTracePath(traceId); _fileSystem.delete(storePath, true); } }