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.Map;
021import java.util.Optional;
022import org.apache.commons.lang3.builder.EqualsBuilder;
023import org.apache.commons.lang3.builder.HashCodeBuilder;
024import org.apache.commons.lang3.builder.ToStringBuilder;
025import org.apache.hadoop.hbase.util.GsonUtil;
026import org.apache.yetus.audience.InterfaceAudience;
027import org.apache.yetus.audience.InterfaceStability;
028
029import org.apache.hbase.thirdparty.com.google.gson.Gson;
030import org.apache.hbase.thirdparty.com.google.gson.JsonObject;
031import org.apache.hbase.thirdparty.com.google.gson.JsonSerializer;
032
033import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
034
035/**
036 * Slow/Large Log payload for hbase-client, to be used by Admin API get_slow_responses and
037 * get_large_responses
038 */
039@InterfaceAudience.Public
040@InterfaceStability.Evolving
041final public class OnlineLogRecord extends LogEntry {
042
043  // used to convert object to pretty printed format
044  // used by toJsonPrettyPrint()
045  private static final Gson GSON =
046    GsonUtil.createGson().setPrettyPrinting().registerTypeAdapter(OnlineLogRecord.class,
047      (JsonSerializer<OnlineLogRecord>) (slowLogPayload, type, jsonSerializationContext) -> {
048        Gson gson = new Gson();
049        JsonObject jsonObj = (JsonObject) gson.toJsonTree(slowLogPayload);
050        if (slowLogPayload.getMultiGetsCount() == 0) {
051          jsonObj.remove("multiGetsCount");
052        }
053        if (slowLogPayload.getMultiMutationsCount() == 0) {
054          jsonObj.remove("multiMutationsCount");
055        }
056        if (slowLogPayload.getMultiServiceCalls() == 0) {
057          jsonObj.remove("multiServiceCalls");
058        }
059        if (slowLogPayload.getRequestAttributes().isEmpty()) {
060          jsonObj.remove("requestAttributes");
061        } else {
062          jsonObj.add("requestAttributes", gson
063            .toJsonTree(ProtobufUtil.deserializeAttributes(slowLogPayload.getRequestAttributes())));
064        }
065        if (slowLogPayload.getConnectionAttributes().isEmpty()) {
066          jsonObj.remove("connectionAttributes");
067        } else {
068          jsonObj.add("connectionAttributes", gson.toJsonTree(
069            ProtobufUtil.deserializeAttributes(slowLogPayload.getConnectionAttributes())));
070        }
071        if (slowLogPayload.getScan().isPresent()) {
072          jsonObj.add("scan", gson.toJsonTree(slowLogPayload.getScan().get().toMap()));
073        } else {
074          jsonObj.remove("scan");
075        }
076        return jsonObj;
077      }).create();
078
079  private final long startTime;
080  private final int processingTime;
081  private final int queueTime;
082  private final long responseSize;
083  private final long blockBytesScanned;
084  private final long fsReadTime;
085  private final String clientAddress;
086  private final String serverClass;
087  private final String methodName;
088  private final String callDetails;
089  private final String param;
090  // we don't want to serialize region name, it is just for the filter purpose
091  // hence avoiding deserialization
092  private final transient String regionName;
093  private final String userName;
094  private final int multiGetsCount;
095  private final int multiMutationsCount;
096  private final int multiServiceCalls;
097  private final Optional<Scan> scan;
098  private final Map<String, byte[]> requestAttributes;
099  private final Map<String, byte[]> connectionAttributes;
100
101  public long getStartTime() {
102    return startTime;
103  }
104
105  public int getProcessingTime() {
106    return processingTime;
107  }
108
109  public int getQueueTime() {
110    return queueTime;
111  }
112
113  public long getResponseSize() {
114    return responseSize;
115  }
116
117  /**
118   * Return the amount of block bytes scanned to retrieve the response cells.
119   */
120  public long getBlockBytesScanned() {
121    return blockBytesScanned;
122  }
123
124  public long getFsReadTime() {
125    return fsReadTime;
126  }
127
128  public String getClientAddress() {
129    return clientAddress;
130  }
131
132  public String getServerClass() {
133    return serverClass;
134  }
135
136  public String getMethodName() {
137    return methodName;
138  }
139
140  public String getCallDetails() {
141    return callDetails;
142  }
143
144  public String getParam() {
145    return param;
146  }
147
148  public String getRegionName() {
149    return regionName;
150  }
151
152  public String getUserName() {
153    return userName;
154  }
155
156  public int getMultiGetsCount() {
157    return multiGetsCount;
158  }
159
160  public int getMultiMutationsCount() {
161    return multiMutationsCount;
162  }
163
164  public int getMultiServiceCalls() {
165    return multiServiceCalls;
166  }
167
168  /**
169   * If {@value org.apache.hadoop.hbase.HConstants#SLOW_LOG_SCAN_PAYLOAD_ENABLED} is enabled then
170   * this value may be present and should represent the Scan that produced the given
171   * {@link OnlineLogRecord}
172   */
173  public Optional<Scan> getScan() {
174    return scan;
175  }
176
177  public Map<String, byte[]> getRequestAttributes() {
178    return requestAttributes;
179  }
180
181  public Map<String, byte[]> getConnectionAttributes() {
182    return connectionAttributes;
183  }
184
185  OnlineLogRecord(final long startTime, final int processingTime, final int queueTime,
186    final long responseSize, final long blockBytesScanned, final long fsReadTime,
187    final String clientAddress, final String serverClass, final String methodName,
188    final String callDetails, final String param, final String regionName, final String userName,
189    final int multiGetsCount, final int multiMutationsCount, final int multiServiceCalls,
190    final Scan scan, final Map<String, byte[]> requestAttributes,
191    final Map<String, byte[]> connectionAttributes) {
192    this.startTime = startTime;
193    this.processingTime = processingTime;
194    this.queueTime = queueTime;
195    this.responseSize = responseSize;
196    this.blockBytesScanned = blockBytesScanned;
197    this.fsReadTime = fsReadTime;
198    this.clientAddress = clientAddress;
199    this.serverClass = serverClass;
200    this.methodName = methodName;
201    this.callDetails = callDetails;
202    this.param = param;
203    this.regionName = regionName;
204    this.userName = userName;
205    this.multiGetsCount = multiGetsCount;
206    this.multiMutationsCount = multiMutationsCount;
207    this.multiServiceCalls = multiServiceCalls;
208    this.scan = Optional.ofNullable(scan);
209    this.requestAttributes = requestAttributes;
210    this.connectionAttributes = connectionAttributes;
211  }
212
213  public static class OnlineLogRecordBuilder {
214    private long startTime;
215    private int processingTime;
216    private int queueTime;
217    private long responseSize;
218    private long blockBytesScanned;
219    private long fsReadTime;
220    private String clientAddress;
221    private String serverClass;
222    private String methodName;
223    private String callDetails;
224    private String param;
225    private String regionName;
226    private String userName;
227    private int multiGetsCount;
228    private int multiMutationsCount;
229    private int multiServiceCalls;
230    private Scan scan = null;
231    private Map<String, byte[]> requestAttributes;
232    private Map<String, byte[]> connectionAttributes;
233
234    public OnlineLogRecordBuilder setStartTime(long startTime) {
235      this.startTime = startTime;
236      return this;
237    }
238
239    public OnlineLogRecordBuilder setProcessingTime(int processingTime) {
240      this.processingTime = processingTime;
241      return this;
242    }
243
244    public OnlineLogRecordBuilder setQueueTime(int queueTime) {
245      this.queueTime = queueTime;
246      return this;
247    }
248
249    public OnlineLogRecordBuilder setResponseSize(long responseSize) {
250      this.responseSize = responseSize;
251      return this;
252    }
253
254    /**
255     * Sets the amount of block bytes scanned to retrieve the response cells.
256     */
257    public OnlineLogRecordBuilder setBlockBytesScanned(long blockBytesScanned) {
258      this.blockBytesScanned = blockBytesScanned;
259      return this;
260    }
261
262    public OnlineLogRecordBuilder setFsReadTime(long fsReadTime) {
263      this.fsReadTime = fsReadTime;
264      return this;
265    }
266
267    public OnlineLogRecordBuilder setClientAddress(String clientAddress) {
268      this.clientAddress = clientAddress;
269      return this;
270    }
271
272    public OnlineLogRecordBuilder setServerClass(String serverClass) {
273      this.serverClass = serverClass;
274      return this;
275    }
276
277    public OnlineLogRecordBuilder setMethodName(String methodName) {
278      this.methodName = methodName;
279      return this;
280    }
281
282    public OnlineLogRecordBuilder setCallDetails(String callDetails) {
283      this.callDetails = callDetails;
284      return this;
285    }
286
287    public OnlineLogRecordBuilder setParam(String param) {
288      this.param = param;
289      return this;
290    }
291
292    public OnlineLogRecordBuilder setRegionName(String regionName) {
293      this.regionName = regionName;
294      return this;
295    }
296
297    public OnlineLogRecordBuilder setUserName(String userName) {
298      this.userName = userName;
299      return this;
300    }
301
302    public OnlineLogRecordBuilder setMultiGetsCount(int multiGetsCount) {
303      this.multiGetsCount = multiGetsCount;
304      return this;
305    }
306
307    public OnlineLogRecordBuilder setMultiMutationsCount(int multiMutationsCount) {
308      this.multiMutationsCount = multiMutationsCount;
309      return this;
310    }
311
312    public OnlineLogRecordBuilder setMultiServiceCalls(int multiServiceCalls) {
313      this.multiServiceCalls = multiServiceCalls;
314      return this;
315    }
316
317    public OnlineLogRecordBuilder setScan(Scan scan) {
318      this.scan = scan;
319      return this;
320    }
321
322    public OnlineLogRecordBuilder setRequestAttributes(Map<String, byte[]> requestAttributes) {
323      this.requestAttributes = requestAttributes;
324      return this;
325    }
326
327    public OnlineLogRecordBuilder
328      setConnectionAttributes(Map<String, byte[]> connectionAttributes) {
329      this.connectionAttributes = connectionAttributes;
330      return this;
331    }
332
333    public OnlineLogRecord build() {
334      return new OnlineLogRecord(startTime, processingTime, queueTime, responseSize,
335        blockBytesScanned, fsReadTime, clientAddress, serverClass, methodName, callDetails, param,
336        regionName, userName, multiGetsCount, multiMutationsCount, multiServiceCalls, scan,
337        requestAttributes, connectionAttributes);
338    }
339  }
340
341  @Override
342  public boolean equals(Object o) {
343    if (this == o) {
344      return true;
345    }
346
347    if (o == null || getClass() != o.getClass()) {
348      return false;
349    }
350
351    OnlineLogRecord that = (OnlineLogRecord) o;
352
353    return new EqualsBuilder().append(startTime, that.startTime)
354      .append(processingTime, that.processingTime).append(queueTime, that.queueTime)
355      .append(responseSize, that.responseSize).append(blockBytesScanned, that.blockBytesScanned)
356      .append(multiGetsCount, that.multiGetsCount)
357      .append(multiMutationsCount, that.multiMutationsCount)
358      .append(multiServiceCalls, that.multiServiceCalls).append(clientAddress, that.clientAddress)
359      .append(serverClass, that.serverClass).append(methodName, that.methodName)
360      .append(callDetails, that.callDetails).append(param, that.param)
361      .append(regionName, that.regionName).append(userName, that.userName).append(scan, that.scan)
362      .append(requestAttributes, that.requestAttributes)
363      .append(connectionAttributes, that.connectionAttributes).isEquals();
364  }
365
366  @Override
367  public int hashCode() {
368    return new HashCodeBuilder(17, 37).append(startTime).append(processingTime).append(queueTime)
369      .append(responseSize).append(blockBytesScanned).append(clientAddress).append(serverClass)
370      .append(methodName).append(callDetails).append(param).append(regionName).append(userName)
371      .append(multiGetsCount).append(multiMutationsCount).append(multiServiceCalls).append(scan)
372      .append(requestAttributes).append(connectionAttributes).toHashCode();
373  }
374
375  @Override
376  public String toJsonPrettyPrint() {
377    return GSON.toJson(this);
378  }
379
380  @Override
381  public String toString() {
382    return new ToStringBuilder(this).append("startTime", startTime)
383      .append("processingTime", processingTime).append("queueTime", queueTime)
384      .append("responseSize", responseSize).append("blockBytesScanned", blockBytesScanned)
385      .append("clientAddress", clientAddress).append("serverClass", serverClass)
386      .append("methodName", methodName).append("callDetails", callDetails).append("param", param)
387      .append("regionName", regionName).append("userName", userName)
388      .append("multiGetsCount", multiGetsCount).append("multiMutationsCount", multiMutationsCount)
389      .append("multiServiceCalls", multiServiceCalls).append("scan", scan)
390      .append("requestAttributes", requestAttributes)
391      .append("connectionAttributes", connectionAttributes).toString();
392  }
393
394}