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 String clientAddress;
085  private final String serverClass;
086  private final String methodName;
087  private final String callDetails;
088  private final String param;
089  // we don't want to serialize region name, it is just for the filter purpose
090  // hence avoiding deserialization
091  private final transient String regionName;
092  private final String userName;
093  private final int multiGetsCount;
094  private final int multiMutationsCount;
095  private final int multiServiceCalls;
096  private final Optional<Scan> scan;
097  private final Map<String, byte[]> requestAttributes;
098  private final Map<String, byte[]> connectionAttributes;
099
100  public long getStartTime() {
101    return startTime;
102  }
103
104  public int getProcessingTime() {
105    return processingTime;
106  }
107
108  public int getQueueTime() {
109    return queueTime;
110  }
111
112  public long getResponseSize() {
113    return responseSize;
114  }
115
116  /**
117   * Return the amount of block bytes scanned to retrieve the response cells.
118   */
119  public long getBlockBytesScanned() {
120    return blockBytesScanned;
121  }
122
123  public String getClientAddress() {
124    return clientAddress;
125  }
126
127  public String getServerClass() {
128    return serverClass;
129  }
130
131  public String getMethodName() {
132    return methodName;
133  }
134
135  public String getCallDetails() {
136    return callDetails;
137  }
138
139  public String getParam() {
140    return param;
141  }
142
143  public String getRegionName() {
144    return regionName;
145  }
146
147  public String getUserName() {
148    return userName;
149  }
150
151  public int getMultiGetsCount() {
152    return multiGetsCount;
153  }
154
155  public int getMultiMutationsCount() {
156    return multiMutationsCount;
157  }
158
159  public int getMultiServiceCalls() {
160    return multiServiceCalls;
161  }
162
163  /**
164   * If {@value org.apache.hadoop.hbase.HConstants#SLOW_LOG_SCAN_PAYLOAD_ENABLED} is enabled then
165   * this value may be present and should represent the Scan that produced the given
166   * {@link OnlineLogRecord}
167   */
168  public Optional<Scan> getScan() {
169    return scan;
170  }
171
172  public Map<String, byte[]> getRequestAttributes() {
173    return requestAttributes;
174  }
175
176  public Map<String, byte[]> getConnectionAttributes() {
177    return connectionAttributes;
178  }
179
180  OnlineLogRecord(final long startTime, final int processingTime, final int queueTime,
181    final long responseSize, final long blockBytesScanned, final String clientAddress,
182    final String serverClass, final String methodName, final String callDetails, final String param,
183    final String regionName, final String userName, final int multiGetsCount,
184    final int multiMutationsCount, final int multiServiceCalls, final Scan scan,
185    final Map<String, byte[]> requestAttributes, final Map<String, byte[]> connectionAttributes) {
186    this.startTime = startTime;
187    this.processingTime = processingTime;
188    this.queueTime = queueTime;
189    this.responseSize = responseSize;
190    this.blockBytesScanned = blockBytesScanned;
191    this.clientAddress = clientAddress;
192    this.serverClass = serverClass;
193    this.methodName = methodName;
194    this.callDetails = callDetails;
195    this.param = param;
196    this.regionName = regionName;
197    this.userName = userName;
198    this.multiGetsCount = multiGetsCount;
199    this.multiMutationsCount = multiMutationsCount;
200    this.multiServiceCalls = multiServiceCalls;
201    this.scan = Optional.ofNullable(scan);
202    this.requestAttributes = requestAttributes;
203    this.connectionAttributes = connectionAttributes;
204  }
205
206  public static class OnlineLogRecordBuilder {
207    private long startTime;
208    private int processingTime;
209    private int queueTime;
210    private long responseSize;
211    private long blockBytesScanned;
212    private String clientAddress;
213    private String serverClass;
214    private String methodName;
215    private String callDetails;
216    private String param;
217    private String regionName;
218    private String userName;
219    private int multiGetsCount;
220    private int multiMutationsCount;
221    private int multiServiceCalls;
222    private Scan scan = null;
223    private Map<String, byte[]> requestAttributes;
224    private Map<String, byte[]> connectionAttributes;
225
226    public OnlineLogRecordBuilder setStartTime(long startTime) {
227      this.startTime = startTime;
228      return this;
229    }
230
231    public OnlineLogRecordBuilder setProcessingTime(int processingTime) {
232      this.processingTime = processingTime;
233      return this;
234    }
235
236    public OnlineLogRecordBuilder setQueueTime(int queueTime) {
237      this.queueTime = queueTime;
238      return this;
239    }
240
241    public OnlineLogRecordBuilder setResponseSize(long responseSize) {
242      this.responseSize = responseSize;
243      return this;
244    }
245
246    /**
247     * Sets the amount of block bytes scanned to retrieve the response cells.
248     */
249    public OnlineLogRecordBuilder setBlockBytesScanned(long blockBytesScanned) {
250      this.blockBytesScanned = blockBytesScanned;
251      return this;
252    }
253
254    public OnlineLogRecordBuilder setClientAddress(String clientAddress) {
255      this.clientAddress = clientAddress;
256      return this;
257    }
258
259    public OnlineLogRecordBuilder setServerClass(String serverClass) {
260      this.serverClass = serverClass;
261      return this;
262    }
263
264    public OnlineLogRecordBuilder setMethodName(String methodName) {
265      this.methodName = methodName;
266      return this;
267    }
268
269    public OnlineLogRecordBuilder setCallDetails(String callDetails) {
270      this.callDetails = callDetails;
271      return this;
272    }
273
274    public OnlineLogRecordBuilder setParam(String param) {
275      this.param = param;
276      return this;
277    }
278
279    public OnlineLogRecordBuilder setRegionName(String regionName) {
280      this.regionName = regionName;
281      return this;
282    }
283
284    public OnlineLogRecordBuilder setUserName(String userName) {
285      this.userName = userName;
286      return this;
287    }
288
289    public OnlineLogRecordBuilder setMultiGetsCount(int multiGetsCount) {
290      this.multiGetsCount = multiGetsCount;
291      return this;
292    }
293
294    public OnlineLogRecordBuilder setMultiMutationsCount(int multiMutationsCount) {
295      this.multiMutationsCount = multiMutationsCount;
296      return this;
297    }
298
299    public OnlineLogRecordBuilder setMultiServiceCalls(int multiServiceCalls) {
300      this.multiServiceCalls = multiServiceCalls;
301      return this;
302    }
303
304    public OnlineLogRecordBuilder setScan(Scan scan) {
305      this.scan = scan;
306      return this;
307    }
308
309    public OnlineLogRecordBuilder setRequestAttributes(Map<String, byte[]> requestAttributes) {
310      this.requestAttributes = requestAttributes;
311      return this;
312    }
313
314    public OnlineLogRecordBuilder
315      setConnectionAttributes(Map<String, byte[]> connectionAttributes) {
316      this.connectionAttributes = connectionAttributes;
317      return this;
318    }
319
320    public OnlineLogRecord build() {
321      return new OnlineLogRecord(startTime, processingTime, queueTime, responseSize,
322        blockBytesScanned, clientAddress, serverClass, methodName, callDetails, param, regionName,
323        userName, multiGetsCount, multiMutationsCount, multiServiceCalls, scan, requestAttributes,
324        connectionAttributes);
325    }
326  }
327
328  @Override
329  public boolean equals(Object o) {
330    if (this == o) {
331      return true;
332    }
333
334    if (o == null || getClass() != o.getClass()) {
335      return false;
336    }
337
338    OnlineLogRecord that = (OnlineLogRecord) o;
339
340    return new EqualsBuilder().append(startTime, that.startTime)
341      .append(processingTime, that.processingTime).append(queueTime, that.queueTime)
342      .append(responseSize, that.responseSize).append(blockBytesScanned, that.blockBytesScanned)
343      .append(multiGetsCount, that.multiGetsCount)
344      .append(multiMutationsCount, that.multiMutationsCount)
345      .append(multiServiceCalls, that.multiServiceCalls).append(clientAddress, that.clientAddress)
346      .append(serverClass, that.serverClass).append(methodName, that.methodName)
347      .append(callDetails, that.callDetails).append(param, that.param)
348      .append(regionName, that.regionName).append(userName, that.userName).append(scan, that.scan)
349      .append(requestAttributes, that.requestAttributes)
350      .append(connectionAttributes, that.connectionAttributes).isEquals();
351  }
352
353  @Override
354  public int hashCode() {
355    return new HashCodeBuilder(17, 37).append(startTime).append(processingTime).append(queueTime)
356      .append(responseSize).append(blockBytesScanned).append(clientAddress).append(serverClass)
357      .append(methodName).append(callDetails).append(param).append(regionName).append(userName)
358      .append(multiGetsCount).append(multiMutationsCount).append(multiServiceCalls).append(scan)
359      .append(requestAttributes).append(connectionAttributes).toHashCode();
360  }
361
362  @Override
363  public String toJsonPrettyPrint() {
364    return GSON.toJson(this);
365  }
366
367  @Override
368  public String toString() {
369    return new ToStringBuilder(this).append("startTime", startTime)
370      .append("processingTime", processingTime).append("queueTime", queueTime)
371      .append("responseSize", responseSize).append("blockBytesScanned", blockBytesScanned)
372      .append("clientAddress", clientAddress).append("serverClass", serverClass)
373      .append("methodName", methodName).append("callDetails", callDetails).append("param", param)
374      .append("regionName", regionName).append("userName", userName)
375      .append("multiGetsCount", multiGetsCount).append("multiMutationsCount", multiMutationsCount)
376      .append("multiServiceCalls", multiServiceCalls).append("scan", scan)
377      .append("requestAttributes", requestAttributes)
378      .append("connectionAttributes", connectionAttributes).toString();
379  }
380
381}