CAT的Client端发送消息

版权声明: https://blog.csdn.net/ph3636/article/details/82463254

1. 生产消息newTransaction,检查上下文ThreadLocal<Context>是否已经初始化,没有则通过m_manager.setup()初始化。初始化消息DefaultTransaction,转交给默认消息管理开始消息处理,m_manager.start(transaction, false);如果是该线程的第一个消息则保存在MessageTree

public void start(Transaction transaction, boolean forked) {
			if (!m_stack.isEmpty()) {
				// Do NOT make strong reference from parent transaction to forked transaction.
				// Instead, we create a "soft" reference to forked transaction later, via linkAsRunAway()
				// By doing so, there is no need for synchronization between parent and child threads.
				// Both threads can complete() anytime despite the other thread.
				Transaction parent = m_stack.peek();
				addTransactionChild(transaction, parent);
			} else {
				m_tree.setMessage(transaction);
			}

			if (!forked) {
				m_stack.push(transaction);
			}
		}

否则就和Stack中的栈顶消息比较生成时间,超过本时段结束时间10s即到达下一时段或者子消息的数量超过配置的最大值,这时深度复制最初的消息以及它的子消息,添加事件消息消息DefaultEvent,最后设置ctx.m_totalDurationInMicros为对应的生成时间,也就表示该值大于0。

public void truncateAndFlush(Context ctx, long timestamp) {
			MessageTree tree = ctx.m_tree;
			Stack<Transaction> stack = ctx.m_stack;
			Message message = tree.getMessage();

			if (message instanceof DefaultTransaction) {
				String id = tree.getMessageId();

				if (id == null) {
					id = nextMessageId();
					tree.setMessageId(id);
				}

				String rootId = tree.getRootMessageId();
				String childId = nextMessageId();
				DefaultTransaction source = (DefaultTransaction) message;
				DefaultTransaction target = new DefaultTransaction(source.getType(), source.getName(),
				      DefaultMessageManager.this);

				target.setTimestamp(source.getTimestamp());
				target.setDurationInMicros(source.getDurationInMicros());
				target.addData(source.getData().toString());
				target.setStatus(Message.SUCCESS);

				migrateMessage(stack, source, target, 1);

				for (int i = stack.size() - 1; i >= 0; i--) {
					DefaultTransaction t = (DefaultTransaction) stack.get(i);

					t.setTimestamp(timestamp);
					t.setDurationStart(System.nanoTime());
				}

				DefaultEvent next = new DefaultEvent("RemoteCall", "Next");

				next.addData(childId);
				next.setStatus(Message.SUCCESS);
				target.addChild(next);

				// tree is the parent, and m_tree is the child.
				MessageTree t = tree.copy();

				t.setMessage(target);

				ctx.m_tree.setMessageId(childId);
				ctx.m_tree.setParentMessageId(id);
				ctx.m_tree.setRootMessageId(rootId != null ? rootId : id);

				ctx.m_length = stack.size();
				ctx.m_totalDurationInMicros = ctx.m_totalDurationInMicros + target.getDurationInMicros();

				flush(t);
			}
		}

最后通过TcpSocketSender#send把他放入不同的队列中,原子队列或者普通消息队列,m_queue.offer(tree, m_manager.getSample()),这里可以设置采样sampleRatio,发送完后执行reset();这时只清除异常信息。最后把当前的消息添加到栈顶消息的子集中,同时记录消息总长度m_length,该值的初始值为1。最后把消息压入栈中。

private void addTransactionChild(Message message, Transaction transaction) {
			long treePeriod = trimToHour(m_tree.getMessage().getTimestamp());
			long messagePeriod = trimToHour(message.getTimestamp() - 10 * 1000L); // 10 seconds extra time allowed

			if (treePeriod < messagePeriod || m_length >= m_configManager.getMaxMessageLength()) {
				m_validator.truncateAndFlush(this, message.getTimestamp());
			}

			transaction.addChild(message);
			m_length++;
		}

2. 设置对应的成功状态h.setStatus(Message.SUCCESS);最后结束消息的构造t.complete();设置完成状态setCompleted(true);结束消息的传送后清除m_context.remove();弹出栈顶的消息,m_validator.validate判断消息有没有正常结尾,也就是设置完成状态,否则增加子事件消息DefaultEvent event = new DefaultEvent("cat", "BadInstrument");设置完成状态

public boolean end(DefaultMessageManager manager, Transaction transaction) {
			if (!m_stack.isEmpty()) {
				Transaction current = m_stack.pop();

				if (transaction == current) {
					m_validator.validate(m_stack.isEmpty() ? null : m_stack.peek(), current);
				} else {
					while (transaction != current && !m_stack.empty()) {
						m_validator.validate(m_stack.peek(), current);

						current = m_stack.pop();
					}
				}

				if (m_stack.isEmpty()) {
					MessageTree tree = m_tree.copy();

					m_tree.setMessageId(null);
					m_tree.setMessage(null);

					if (m_totalDurationInMicros > 0) {
						adjustForTruncatedTransaction((Transaction) tree.getMessage());
					}

					manager.flush(tree);
					return true;
				}
			}

			return false;
		}

那什么时候才会进入下面这个else呢?开始transactionA,开始transactionB,但是完成的时候是transactionA,transactionB。正确的做法是transactionB,transactionA。否则这个时候就会给强制给transactionB设置完成状态。

public void validate(Transaction parent, Transaction transaction) {
			if (transaction.isStandalone()) {
				List<Message> children = transaction.getChildren();
				int len = children.size();

				for (int i = 0; i < len; i++) {
					Message message = children.get(i);

					if (message instanceof Transaction) {
						validate(transaction, (Transaction) message);
					}
				}

				if (!transaction.isCompleted() && transaction instanceof DefaultTransaction) {
					// missing transaction end, log a BadInstrument event so that
					// developer can fix the code
					markAsNotCompleted((DefaultTransaction) transaction);
				}
			} 
		}
private void markAsNotCompleted(DefaultTransaction transaction) {
			DefaultEvent event = new DefaultEvent("cat", "BadInstrument");

			event.setStatus("TransactionNotCompleted");
			event.setCompleted(true);
			transaction.addChild(event);
			transaction.setCompleted(true);
		}

这个m_stack.isEmpty()又是怎么起作用的?如果是上面这个错误情况的话,这个条件可以满足,还有就是正常情况下,当transactionB设置完成状态时,这个条件不会满足,也就不会给发送消息,进而也能保证整个流程的顺利执行,当transactionA设置完成状态之后,m_stack.isEmpty()就会满足,然后发送消息。检验完栈中所有的元素后,深拷贝最初的消息MessageTree,释放最初的消息,最后把消息通过TcpSocketSender发送到消息队列中。

如果之前生成消息的时候超过了时间或者数量限制的话,就会产生截断信息,也就是m_totalDurationInMicros会大于0,这是就会给根消息增加子事件消息,并且设置m_totalDurationInMicros = 0

private void adjustForTruncatedTransaction(Transaction root) {
			DefaultEvent next = new DefaultEvent("TruncatedTransaction", "TotalDuration");
			long actualDurationInMicros = m_totalDurationInMicros + root.getDurationInMicros();

			next.addData(String.valueOf(actualDurationInMicros));
			next.setStatus(Message.SUCCESS);
			root.addChild(next);

			m_totalDurationInMicros = 0;
		}

发送完后调用reset();清理栈,移除线程上下文等。那ctx.m_totalDurationInMicros == 0该条件什么时候满足呢,一个就是整个线程中的消息没有超过时间或者数量限制,这时m_totalDurationInMicros的默认值就是0,另一个情况就是超过限制,如上,在截断后给该值设置为0,保证该线程结束后能清理掉该清理的线程上下文,栈变量等。

public void reset() {
		// destroy current thread local data
		Context ctx = m_context.get();

		if (ctx != null) {
			if (ctx.m_totalDurationInMicros == 0) {
				ctx.m_stack.clear();
				ctx.m_knownExceptions.clear();
				m_context.remove();
			} else {
				ctx.m_knownExceptions.clear();
			}
		}
	}

猜你喜欢

转载自blog.csdn.net/ph3636/article/details/82463254