| // 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.cloudstack.context; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.UUID; |
| |
| import org.apache.log4j.Logger; |
| import org.slf4j.MDC; |
| |
| import org.apache.cloudstack.managed.threadlocal.ManagedThreadLocal; |
| |
| import com.cloud.exception.CloudAuthenticationException; |
| import com.cloud.user.Account; |
| import com.cloud.user.User; |
| import com.cloud.utils.UuidUtils; |
| import com.cloud.utils.db.EntityManager; |
| import com.cloud.utils.exception.CloudRuntimeException; |
| |
| /** |
| * LogContext records information about the environment the API call is made. This |
| * class must be always be available in all CloudStack code. |
| */ |
| public class LogContext { |
| private static final Logger s_logger = Logger.getLogger(LogContext.class); |
| private static ManagedThreadLocal<LogContext> s_currentContext = new ManagedThreadLocal<LogContext>(); |
| |
| private String logContextId; |
| private Account account; |
| private long accountId; |
| private long startEventId = 0; |
| private String eventDescription; |
| private String eventDetails; |
| private String eventType; |
| private boolean isEventDisplayEnabled = true; // default to true unless specifically set |
| private User user; |
| private long userId; |
| private final Map<String, String> context = new HashMap<String, String>(); |
| |
| static EntityManager s_entityMgr; |
| |
| public static void init(EntityManager entityMgr) { |
| s_entityMgr = entityMgr; |
| } |
| |
| protected LogContext() { |
| } |
| |
| protected LogContext(long userId, long accountId, String logContextId) { |
| this.userId = userId; |
| this.accountId = accountId; |
| this.logContextId = logContextId; |
| } |
| |
| protected LogContext(User user, Account account, String logContextId) { |
| this.user = user; |
| userId = user.getId(); |
| this.account = account; |
| accountId = account.getId(); |
| this.logContextId = logContextId; |
| } |
| |
| public void putContextParameter(String key, String value) { |
| context.put(key, value); |
| } |
| |
| public String getContextParameter(String key) { |
| return context.get(key); |
| } |
| |
| public long getCallingUserId() { |
| return userId; |
| } |
| |
| public User getCallingUser() { |
| if (user == null) { |
| user = s_entityMgr.findById(User.class, userId); |
| } |
| return user; |
| } |
| |
| public String getLogContextId() { |
| return logContextId; |
| } |
| |
| public Account getCallingAccount() { |
| if (account == null) { |
| account = s_entityMgr.findById(Account.class, accountId); |
| } |
| return account; |
| } |
| |
| public static LogContext current() { |
| LogContext context = s_currentContext.get(); |
| if (context == null) { |
| context = registerSystemLogContextOnceOnly(); |
| } |
| return context; |
| } |
| |
| /** |
| * This method should only be called if you can propagate the context id |
| * from another LogContext. |
| * |
| * @param callingUser calling user |
| * @param callingAccount calling account |
| * @param contextId context id propagated from another call context |
| * @return LogContext |
| */ |
| public static LogContext register(User callingUser, Account callingAccount, String contextId) { |
| return register(callingUser, callingAccount, null, null, contextId); |
| } |
| |
| protected static LogContext register(User callingUser, Account callingAccount, Long userId, Long accountId, String contextId) { |
| LogContext callingContext = null; |
| if (userId == null || accountId == null) { |
| callingContext = new LogContext(callingUser, callingAccount, contextId); |
| } else { |
| callingContext = new LogContext(userId, accountId, contextId); |
| } |
| s_currentContext.set(callingContext); |
| MDC.put("logcontextid", UuidUtils.first(contextId)); |
| if (s_logger.isTraceEnabled()) { |
| s_logger.trace("Registered for log: " + callingContext); |
| } |
| return callingContext; |
| } |
| |
| public static LogContext registerPlaceHolderContext() { |
| LogContext context = new LogContext(0, 0, UUID.randomUUID().toString()); |
| s_currentContext.set(context); |
| return context; |
| } |
| |
| public static LogContext register(User callingUser, Account callingAccount) { |
| return register(callingUser, callingAccount, UUID.randomUUID().toString()); |
| } |
| |
| public static LogContext registerSystemLogContextOnceOnly() { |
| try { |
| LogContext context = s_currentContext.get(); |
| if (context == null) { |
| return register(null, null, User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, UUID.randomUUID().toString()); |
| } |
| assert context.getCallingUserId() == User.UID_SYSTEM : "You are calling a very specific method that registers a one time system context. This method is meant for background threads that does processing."; |
| return context; |
| } catch (Exception e) { |
| s_logger.error("Failed to register the system log context.", e); |
| throw new CloudRuntimeException("Failed to register system log context", e); |
| } |
| } |
| |
| public static LogContext register(String callingUserUuid, String callingAccountUuid) { |
| Account account = s_entityMgr.findByUuid(Account.class, callingAccountUuid); |
| if (account == null) { |
| throw new CloudAuthenticationException("The account is no longer current.").add(Account.class, callingAccountUuid); |
| } |
| |
| User user = s_entityMgr.findByUuid(User.class, callingUserUuid); |
| if (user == null) { |
| throw new CloudAuthenticationException("The user is no longer current.").add(User.class, callingUserUuid); |
| } |
| return register(user, account); |
| } |
| |
| public static LogContext register(long callingUserId, long callingAccountId) throws CloudAuthenticationException { |
| Account account = s_entityMgr.findById(Account.class, callingAccountId); |
| if (account == null) { |
| throw new CloudAuthenticationException("The account is no longer current.").add(Account.class, Long.toString(callingAccountId)); |
| } |
| User user = s_entityMgr.findById(User.class, callingUserId); |
| if (user == null) { |
| throw new CloudAuthenticationException("The user is no longer current.").add(User.class, Long.toString(callingUserId)); |
| } |
| return register(user, account); |
| } |
| |
| public static LogContext register(long callingUserId, long callingAccountId, String contextId) throws CloudAuthenticationException { |
| Account account = s_entityMgr.findById(Account.class, callingAccountId); |
| if (account == null) { |
| throw new CloudAuthenticationException("The account is no longer current.").add(Account.class, Long.toString(callingAccountId)); |
| } |
| User user = s_entityMgr.findById(User.class, callingUserId); |
| if (user == null) { |
| throw new CloudAuthenticationException("The user is no longer current.").add(User.class, Long.toString(callingUserId)); |
| } |
| return register(user, account, contextId); |
| } |
| |
| public static void unregister() { |
| LogContext context = s_currentContext.get(); |
| if (context != null) { |
| s_currentContext.remove(); |
| if (s_logger.isTraceEnabled()) { |
| s_logger.trace("Unregistered: " + context); |
| } |
| } |
| MDC.clear(); |
| } |
| |
| public void setStartEventId(long startEventId) { |
| this.startEventId = startEventId; |
| } |
| |
| public long getStartEventId() { |
| return startEventId; |
| } |
| |
| public long getCallingAccountId() { |
| return accountId; |
| } |
| |
| public String getCallingAccountUuid() { |
| return getCallingAccount().getUuid(); |
| } |
| |
| public String getCallingUserUuid() { |
| return getCallingUser().getUuid(); |
| } |
| |
| public void setEventDetails(String eventDetails) { |
| this.eventDetails = eventDetails; |
| } |
| |
| public String getEventDetails() { |
| return eventDetails; |
| } |
| |
| public String getEventType() { |
| return eventType; |
| } |
| |
| public void setEventType(String eventType) { |
| this.eventType = eventType; |
| } |
| |
| public String getEventDescription() { |
| return eventDescription; |
| } |
| |
| public void setEventDescription(String eventDescription) { |
| this.eventDescription = eventDescription; |
| } |
| |
| /** |
| * Whether to display the event to the end user. |
| * @return true - if the event is to be displayed to the end user, false otherwise. |
| */ |
| public boolean isEventDisplayEnabled() { |
| return isEventDisplayEnabled; |
| } |
| |
| public void setEventDisplayEnabled(boolean eventDisplayEnabled) { |
| isEventDisplayEnabled = eventDisplayEnabled; |
| } |
| |
| public Map<String, String> getContextParameters() { |
| return context; |
| } |
| |
| public void putContextParameters(Map<String, String> details) { |
| if (details == null) |
| return; |
| for (Map.Entry<String, String> entry : details.entrySet()) { |
| putContextParameter(entry.getKey(), entry.getValue()); |
| } |
| } |
| |
| public static void setActionEventInfo(String eventType, String description) { |
| LogContext context = LogContext.current(); |
| if (context != null) { |
| context.setEventType(eventType); |
| context.setEventDescription(description); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return new StringBuilder("LogCtxt[acct=").append(getCallingAccountId()) |
| .append("; user=") |
| .append(getCallingUserId()) |
| .append("; id=") |
| .append(logContextId) |
| .append("]") |
| .toString(); |
| } |
| } |