All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dianping.cat.analyzer.TransactionAggregator Maven / Gradle / Ivy

/*
 * Copyright (c) 2011-2018, Meituan Dianping. All Rights Reserved.
 *
 * 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 com.dianping.cat.analyzer;

import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.configuration.ClientConfigManager;
import com.dianping.cat.configuration.ProblemLongType;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.spi.MessageTree;

import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class TransactionAggregator {

	private static TransactionAggregator s_instance = new TransactionAggregator();

	private volatile ConcurrentHashMap> m_transactions = new ConcurrentHashMap>();

	public static TransactionAggregator getInstance() {
		return s_instance;
	}

	private TransactionData createTransactionData(String type, String name) {
		return new TransactionData(type, name);
	}

	public ConcurrentHashMap> getAndResetTransactions() {
		ConcurrentHashMap> cloned = m_transactions;

		m_transactions = new ConcurrentHashMap>();

		for (Entry> entry : cloned.entrySet()) {
			String type = entry.getKey();

			m_transactions.putIfAbsent(type, new ConcurrentHashMap());
		}

		return cloned;
	}

	public String getDomain(MessageTree tree) {
		return Cat.getManager().getDomain();
	}

	public void logBatchTransaction(String type, String name, int count, int error, long sum) {
		makeSureTransactionExist(type, name).add(count, error, sum);
	}

	public void logTransaction(Transaction t) {
		makeSureTransactionExist(t.getType(), t.getName()).add(t);
	}

	private TransactionData makeSureTransactionExist(String type, String name) {
		ConcurrentHashMap item = m_transactions.get(type);

		if (null == item) {
			item = new ConcurrentHashMap();

			ConcurrentHashMap oldValue = m_transactions.putIfAbsent(type, item);

			if (oldValue != null) {
				item = oldValue;
			}
		}

		TransactionData data = item.get(name);

		if (null == data) {
			data = createTransactionData(type, name);

			TransactionData oldValue = item.putIfAbsent(name, data);

			if (oldValue == null) {
				return data;
			} else {
				return oldValue;
			}
		}

		return data;
	}

	public void sendTransactionData() {
		ConcurrentHashMap> transactions = getAndResetTransactions();
		boolean hasData = false;

		for (Map entry : transactions.values()) {
			for (TransactionData data : entry.values()) {
				if (data.getCount().get() > 0) {
					hasData = true;
					break;
				}
			}
		}

		if (hasData) {
			Transaction t = Cat.newTransaction(CatConstants.CAT_SYSTEM, this.getClass().getSimpleName());
			MessageTree tree = Cat.getManager().getThreadLocalMessageTree();

			tree.setDomain(getDomain(tree));
			tree.setDiscardPrivate(false);

			for (Map entry : transactions.values()) {
				for (TransactionData data : entry.values()) {
					if (data.getCount().get() > 0) {
						Transaction tmp = Cat.newTransaction(data.getType(), data.getName());
						StringBuilder sb = new StringBuilder(32);

						sb.append(CatConstants.BATCH_FLAG).append(data.getCount().get()).append(CatConstants.SPLIT);
						sb.append(data.getFail().get()).append(CatConstants.SPLIT);
						sb.append(data.getSum().get()).append(CatConstants.SPLIT);
						sb.append(data.getDurationString()).append(CatConstants.SPLIT).append(data.getLongDurationString());

						tmp.addData(sb.toString());
						tmp.setSuccessStatus();
						tmp.complete();
					}
				}
			}
			t.setSuccessStatus();
			t.complete();
		}
	}

	private int checkAndGetLongThreshold(String type, int duration) {
		ClientConfigManager config = Cat.getManager().getConfigManager();
		ProblemLongType longType = ProblemLongType.findByMessageType(type);

		if (longType != null) {
			switch (longType) {
			case LONG_CACHE:
				return config.getLongThresholdByDuration(ProblemLongType.LONG_CACHE.getName(), duration);
			case LONG_CALL:
				return config.getLongThresholdByDuration(ProblemLongType.LONG_CALL.getName(), duration);
			case LONG_SERVICE:
				return config.getLongThresholdByDuration(ProblemLongType.LONG_SERVICE.getName(), duration);
			case LONG_SQL:
				return config.getLongThresholdByDuration(ProblemLongType.LONG_SQL.getName(), duration);
			case LONG_URL:
				return config.getLongThresholdByDuration(ProblemLongType.LONG_URL.getName(), duration);
			case LONG_MQ:
				return config.getLongThresholdByDuration(ProblemLongType.LONG_MQ.getName(), duration);
			}
		}
		return -1;
	}

	public class TransactionData {

		private String m_type;

		private String m_name;

		private AtomicInteger m_count = new AtomicInteger();

		private AtomicInteger m_fail = new AtomicInteger();

		private AtomicLong m_sum = new AtomicLong();

		private ConcurrentHashMap m_durations = new ConcurrentHashMap();

		private ConcurrentHashMap m_longDurations = new ConcurrentHashMap();

		public TransactionData(String type, String name) {
			m_type = type;
			m_name = name;
		}

		public TransactionData add(int count, int error, long sum) {
			m_count.addAndGet(count);
			m_sum.addAndGet(sum);
			m_fail.addAndGet(error);

			if (count == 1) {
				int duration = DurationComputer.computeDuration((int) sum);
				AtomicInteger durationCount = m_durations.get(duration);

				if (durationCount == null) {
					m_durations.put(duration, new AtomicInteger(1));
				} else {
					durationCount.incrementAndGet();
				}
			}

			return this;
		}

		public TransactionData add(Transaction t) {
			m_count.incrementAndGet();
			m_sum.getAndAdd(t.getDurationInMillis());

			if (!t.isSuccess()) {
				m_fail.incrementAndGet();
			}

			int duration = DurationComputer.computeDuration((int) t.getDurationInMillis());
			AtomicInteger count = m_durations.get(duration);

			if (count == null) {
				count = new AtomicInteger(0);

				AtomicInteger oldCount = m_durations.putIfAbsent(duration, count);

				if (oldCount != null) {
					count = oldCount;
				}
			}
			count.incrementAndGet();

			int longDuration = checkAndGetLongThreshold(t.getType(), duration);

			if (longDuration > 0) {
				AtomicInteger longCount = m_longDurations.get(longDuration);

				if (longCount == null) {
					longCount = new AtomicInteger(0);

					AtomicInteger oldLongCount = m_longDurations.putIfAbsent(longDuration, longCount);

					if (oldLongCount != null) {
						longCount = oldLongCount;
					}
				}
				longCount.incrementAndGet();
			}
			return this;
		}

		public AtomicInteger getCount() {
			return m_count;
		}

		public Map getDurations() {
			return m_durations;
		}

		public String getDurationString() {
			StringBuilder sb = new StringBuilder();
			boolean first = true;

			for (Entry entry : m_durations.entrySet()) {
				Integer key = entry.getKey();
				AtomicInteger value = entry.getValue();

				if (first) {
					sb.append(key).append(',').append(value);
					first = false;
				} else {
					sb.append('|').append(key).append(',').append(value);
				}
			}

			return sb.toString();
		}

		public Map getLongDurations() {
			return m_longDurations;
		}

		public String getLongDurationString() {
			StringBuilder sb = new StringBuilder();
			boolean first = true;

			for (Entry entry : m_longDurations.entrySet()) {
				Integer key = entry.getKey();
				AtomicInteger value = entry.getValue();

				if (first) {
					sb.append(key).append(',').append(value);
					first = false;
				} else {
					sb.append('|').append(key).append(',').append(value);
				}
			}

			return sb.toString();
		}

		public AtomicInteger getFail() {
			return m_fail;
		}

		public String getName() {
			return m_name;
		}

		public AtomicLong getSum() {
			return m_sum;
		}

		public String getType() {
			return m_type;
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy