001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import java.util.Optional;
021import org.apache.commons.lang3.builder.EqualsBuilder;
022import org.apache.commons.lang3.builder.HashCodeBuilder;
023import org.apache.commons.lang3.builder.ToStringBuilder;
024import org.apache.hadoop.hbase.util.GsonUtil;
025import org.apache.yetus.audience.InterfaceAudience;
026import org.apache.yetus.audience.InterfaceStability;
027
028import org.apache.hbase.thirdparty.com.google.gson.Gson;
029import org.apache.hbase.thirdparty.com.google.gson.JsonObject;
030import org.apache.hbase.thirdparty.com.google.gson.JsonSerializer;
031
032/**
033 * Slow/Large Log payload for hbase-client, to be used by Admin API get_slow_responses and
034 * get_large_responses
035 */
036@InterfaceAudience.Public
037@InterfaceStability.Evolving
038final public class OnlineLogRecord extends LogEntry {
039
040  // used to convert object to pretty printed format
041  // used by toJsonPrettyPrint()
042  private static final Gson GSON =
043    GsonUtil.createGson().setPrettyPrinting().registerTypeAdapter(OnlineLogRecord.class,
044      (JsonSerializer<OnlineLogRecord>) (slowLogPayload, type, jsonSerializationContext) -> {
045        Gson gson = new Gson();
046        JsonObject jsonObj = (JsonObject) gson.toJsonTree(slowLogPayload);
047        if (slowLogPayload.getMultiGetsCount() == 0) {
048          jsonObj.remove("multiGetsCount");
049        }
050        if (slowLogPayload.getMultiMutationsCount() == 0) {
051          jsonObj.remove("multiMutationsCount");
052        }
053        if (slowLogPayload.getMultiServiceCalls() == 0) {
054          jsonObj.remove("multiServiceCalls");
055        }
056        if (slowLogPayload.getScan().isPresent()) {
057          jsonObj.add("scan", gson.toJsonTree(slowLogPayload.getScan().get().toMap()));
058        } else {
059          jsonObj.remove("scan");
060        }
061        return jsonObj;
062      }).create();
063
064  private final long startTime;
065  private final int processingTime;
066  private final int queueTime;
067  private final long responseSize;
068  private final long blockBytesScanned;
069  private final String clientAddress;
070  private final String serverClass;
071  private final String methodName;
072  private final String callDetails;
073  private final String param;
074  // we don't want to serialize region name, it is just for the filter purpose
075  // hence avoiding deserialization
076  private final transient String regionName;
077  private final String userName;
078  private final int multiGetsCount;
079  private final int multiMutationsCount;
080  private final int multiServiceCalls;
081  private final Optional<Scan> scan;
082
083  public long getStartTime() {
084    return startTime;
085  }
086
087  public int getProcessingTime() {
088    return processingTime;
089  }
090
091  public int getQueueTime() {
092    return queueTime;
093  }
094
095  public long getResponseSize() {
096    return responseSize;
097  }
098
099  /**
100   * Return the amount of block bytes scanned to retrieve the response cells.
101   */
102  public long getBlockBytesScanned() {
103    return blockBytesScanned;
104  }
105
106  public String getClientAddress() {
107    return clientAddress;
108  }
109
110  public String getServerClass() {
111    return serverClass;
112  }
113
114  public String getMethodName() {
115    return methodName;
116  }
117
118  public String getCallDetails() {
119    return callDetails;
120  }
121
122  public String getParam() {
123    return param;
124  }
125
126  public String getRegionName() {
127    return regionName;
128  }
129
130  public String getUserName() {
131    return userName;
132  }
133
134  public int getMultiGetsCount() {
135    return multiGetsCount;
136  }
137
138  public int getMultiMutationsCount() {
139    return multiMutationsCount;
140  }
141
142  public int getMultiServiceCalls() {
143    return multiServiceCalls;
144  }
145
146  /**
147   * If {@value org.apache.hadoop.hbase.HConstants#SLOW_LOG_SCAN_PAYLOAD_ENABLED} is enabled then
148   * this value may be present and should represent the Scan that produced the given
149   * {@link OnlineLogRecord}
150   */
151  public Optional<Scan> getScan() {
152    return scan;
153  }
154
155  OnlineLogRecord(final long startTime, final int processingTime, final int queueTime,
156    final long responseSize, final long blockBytesScanned, final String clientAddress,
157    final String serverClass, final String methodName, final String callDetails, final String param,
158    final String regionName, final String userName, final int multiGetsCount,
159    final int multiMutationsCount, final int multiServiceCalls, final Scan scan) {
160    this.startTime = startTime;
161    this.processingTime = processingTime;
162    this.queueTime = queueTime;
163    this.responseSize = responseSize;
164    this.blockBytesScanned = blockBytesScanned;
165    this.clientAddress = clientAddress;
166    this.serverClass = serverClass;
167    this.methodName = methodName;
168    this.callDetails = callDetails;
169    this.param = param;
170    this.regionName = regionName;
171    this.userName = userName;
172    this.multiGetsCount = multiGetsCount;
173    this.multiMutationsCount = multiMutationsCount;
174    this.multiServiceCalls = multiServiceCalls;
175    this.scan = Optional.ofNullable(scan);
176  }
177
178  public static class OnlineLogRecordBuilder {
179    private long startTime;
180    private int processingTime;
181    private int queueTime;
182    private long responseSize;
183    private long blockBytesScanned;
184    private String clientAddress;
185    private String serverClass;
186    private String methodName;
187    private String callDetails;
188    private String param;
189    private String regionName;
190    private String userName;
191    private int multiGetsCount;
192    private int multiMutationsCount;
193    private int multiServiceCalls;
194    private Scan scan = null;
195
196    public OnlineLogRecordBuilder setStartTime(long startTime) {
197      this.startTime = startTime;
198      return this;
199    }
200
201    public OnlineLogRecordBuilder setProcessingTime(int processingTime) {
202      this.processingTime = processingTime;
203      return this;
204    }
205
206    public OnlineLogRecordBuilder setQueueTime(int queueTime) {
207      this.queueTime = queueTime;
208      return this;
209    }
210
211    public OnlineLogRecordBuilder setResponseSize(long responseSize) {
212      this.responseSize = responseSize;
213      return this;
214    }
215
216    /**
217     * Sets the amount of block bytes scanned to retrieve the response cells.
218     */
219    public OnlineLogRecordBuilder setBlockBytesScanned(long blockBytesScanned) {
220      this.blockBytesScanned = blockBytesScanned;
221      return this;
222    }
223
224    public OnlineLogRecordBuilder setClientAddress(String clientAddress) {
225      this.clientAddress = clientAddress;
226      return this;
227    }
228
229    public OnlineLogRecordBuilder setServerClass(String serverClass) {
230      this.serverClass = serverClass;
231      return this;
232    }
233
234    public OnlineLogRecordBuilder setMethodName(String methodName) {
235      this.methodName = methodName;
236      return this;
237    }
238
239    public OnlineLogRecordBuilder setCallDetails(String callDetails) {
240      this.callDetails = callDetails;
241      return this;
242    }
243
244    public OnlineLogRecordBuilder setParam(String param) {
245      this.param = param;
246      return this;
247    }
248
249    public OnlineLogRecordBuilder setRegionName(String regionName) {
250      this.regionName = regionName;
251      return this;
252    }
253
254    public OnlineLogRecordBuilder setUserName(String userName) {
255      this.userName = userName;
256      return this;
257    }
258
259    public OnlineLogRecordBuilder setMultiGetsCount(int multiGetsCount) {
260      this.multiGetsCount = multiGetsCount;
261      return this;
262    }
263
264    public OnlineLogRecordBuilder setMultiMutationsCount(int multiMutationsCount) {
265      this.multiMutationsCount = multiMutationsCount;
266      return this;
267    }
268
269    public OnlineLogRecordBuilder setMultiServiceCalls(int multiServiceCalls) {
270      this.multiServiceCalls = multiServiceCalls;
271      return this;
272    }
273
274    public OnlineLogRecordBuilder setScan(Scan scan) {
275      this.scan = scan;
276      return this;
277    }
278
279    public OnlineLogRecord build() {
280      return new OnlineLogRecord(startTime, processingTime, queueTime, responseSize,
281        blockBytesScanned, clientAddress, serverClass, methodName, callDetails, param, regionName,
282        userName, multiGetsCount, multiMutationsCount, multiServiceCalls, scan);
283    }
284  }
285
286  @Override
287  public boolean equals(Object o) {
288    if (this == o) {
289      return true;
290    }
291
292    if (o == null || getClass() != o.getClass()) {
293      return false;
294    }
295
296    OnlineLogRecord that = (OnlineLogRecord) o;
297
298    return new EqualsBuilder().append(startTime, that.startTime)
299      .append(processingTime, that.processingTime).append(queueTime, that.queueTime)
300      .append(responseSize, that.responseSize).append(blockBytesScanned, that.blockBytesScanned)
301      .append(multiGetsCount, that.multiGetsCount)
302      .append(multiMutationsCount, that.multiMutationsCount)
303      .append(multiServiceCalls, that.multiServiceCalls).append(clientAddress, that.clientAddress)
304      .append(serverClass, that.serverClass).append(methodName, that.methodName)
305      .append(callDetails, that.callDetails).append(param, that.param)
306      .append(regionName, that.regionName).append(userName, that.userName).append(scan, that.scan)
307      .isEquals();
308  }
309
310  @Override
311  public int hashCode() {
312    return new HashCodeBuilder(17, 37).append(startTime).append(processingTime).append(queueTime)
313      .append(responseSize).append(blockBytesScanned).append(clientAddress).append(serverClass)
314      .append(methodName).append(callDetails).append(param).append(regionName).append(userName)
315      .append(multiGetsCount).append(multiMutationsCount).append(multiServiceCalls).append(scan)
316      .toHashCode();
317  }
318
319  @Override
320  public String toJsonPrettyPrint() {
321    return GSON.toJson(this);
322  }
323
324  @Override
325  public String toString() {
326    return new ToStringBuilder(this).append("startTime", startTime)
327      .append("processingTime", processingTime).append("queueTime", queueTime)
328      .append("responseSize", responseSize).append("blockBytesScanned", blockBytesScanned)
329      .append("clientAddress", clientAddress).append("serverClass", serverClass)
330      .append("methodName", methodName).append("callDetails", callDetails).append("param", param)
331      .append("regionName", regionName).append("userName", userName)
332      .append("multiGetsCount", multiGetsCount).append("multiMutationsCount", multiMutationsCount)
333      .append("multiServiceCalls", multiServiceCalls).append("scan", scan).toString();
334  }
335
336}